1

我在一个项目中有以下设计

  • 多个爬虫
  • 找到的图像列表ImageList( Observable); 这由线程进程更新(因此是并行的)
  • 两个监听列表(DownloaderImagesWindow)的观察者;警告:这些可以被多次通知,因为列表是由线程更新的

我一直想只获取最新的条目,ImageList所以我用一个计数器实现了它:

public class ImageList extends Observable {
    private final ConcurrentMap<Integer, Image> images = new ConcurrentHashMap<Integer, Image>();
    private final AtomicInteger counter = new AtomicInteger(0);

    /* There is some more code within here, but its not that important
       important is that stuff gets added to the list and the list shall
       inform all listeners about the change

       The observers then check which is the newest ID in the list (often +1
       but I guess I will reduce the inform frequency somehow)
       and call (in synchronized method):

       int lastIndex = list.getCurrentLastIndex();
       getImagesFromTo(myNextValue, lastIndex);
       myNextValue = lastIndex + 1;
    */

    public synchronized void addToFinished(Image job) throws InterruptedException {
        int currentCounter = counter.incrementAndGet();

        images.put(currentCounter, job);

        this.setChanged();
        this.notifyObservers();
    }

    public synchronized int getCurrentLastIndex() {
        return counter.get();
    }

    public ArrayList<Image> getImagesFromTo(int starting, int ending) {
        ArrayList<Image> newImages = new ArrayList<Image>();

        Image image;
        for (int i = starting; i <= ending; i++) {
            image = images.get(i);
            if (image != null) {
                newImages.add(image);
            }
        }

        return newImages;
    }
}

观察者(Downloader这里)使用这种方法是这样的:

@Override
public void update(Observable o, Object arg) {
    System.out.println("Updated downloader");

    if (o instanceof ImageList) {
        ImageList list = (ImageList) o;
        downloadNewImages(list);
    }
}

private synchronized void downloadNewImages(ImageList list) {
    int last = list.getCurrentLastIndex();

    for (Image image : list.getImagesFromTo(readImageFrom, last)) {
        // code gets stuck after this line
        if (filter.isOk(image)) {
            // and before this line
            // [here was a line, but it also fails if I remove it]
        }
    }

    // set the index to the new index
    readImageFrom = last + 1;
}

但是,有时循环会卡住,并且似乎允许对该方法进行第二次调用。然后这就是发生的事情:

  • 下载器检索图像 70 到 70
  • 下载器检索图像 70 到 71
  • 下载器检索图像 70 到 72
  • …</li>
  • 下载器检索图像 70 到 n

因此,允许对该方法的第二次调用进入该方法,但计数器readImageFrom永远不会更新。

当我删除对循环中其他函数的两个调用时,脚本开始工作。我知道它们没有同步,但是如果“父级”已经同步,它们是否必须同步?

filter.isOK()是这样实现的(其他函数只返回 true 或 false;当我hasRightColor包含代码时代码失败,我猜是因为计算速度有点慢):

public boolean isOk(Image image) {
    return hasRightDimensions(image) && hasRightColor(image);
}

这怎么可能发生?Eclipse 不会显示任何抛出的异常(这当然会导致方法退出)。

也许还有一种完全不同的方法可以只从多个观察者那里获取列表的最新内容(每个观察者可能会被通知多次,因为程序并行运行)?

4

1 回答 1

0

好的,错误是一些邪恶的NullPointerException没有显示给我(谁知道为什么)filter.isOk()

我无法在我的 IDE 中看到它,因为我已从更改this.image为 parameter-passing image,但忘记private image在标题中删除并更改三个函数中最后一个函数的参数。

所以 Eclipse 既没有说任何关于缺失的事情,也没有说image关于未使用的this.image.

最后。

于 2012-07-14T15:11:14.617 回答