调用函数卡住,但监视器似乎被释放了,怎么样?

时间:2012-07-14 10:56:02

标签: java parallel-processing

我在项目中有以下设计

  • 多个抓取工具
  • 找到图片的列表ImageListObservable);这会由线程进程(因此并行)
  • 更新
  • 两位听取名单的观察员(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
  • ...
  • 下载程序检索图像70到n

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

当我删除对循环中其他函数的两次调用时,脚本开始工作。我知道他们没有同步,但如果已经“父”同步了,他们必须这样做吗?

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

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

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

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

1 个答案:

答案 0 :(得分:0)

好的,错误是一些邪恶的 NullPointerException filter.isOk()中没有向我显示(谁知道原因)。

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

因此,eclipse既没有说明遗失image也没有说明未使用的this.image

最后。