1

私はプロジェクトで次のデザインを持っています

  • 複数のクローラー
  • ImageList見つかった画像のリスト( Observable); これはスレッド化されたプロセスによって更新されます(したがって並列)
  • リストを聞く2人のオブザーバー(DownloaderおよびImagesWindow); 警告:リストはスレッドによって更新されるため、これらは複数回通知される可能性があります

私は常に最新のエントリのみを取得したかったので、カウンター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;
}

ただし、ループがスタックし、メソッドで2番目の呼び出しが許可されているように見える場合があります。次に、これが起こります:

  • ダウンローダーは70から70の画像を取得します
  • ダウンローダーは70から71の画像を取得します
  • ダウンローダーは70から72の画像を取得します
  • …</li>
  • ダウンローダーは70からnまでの画像を取得します

したがって、メソッドへの2回目の呼び出しはメソッドへの入力を許可されますが、カウンターreadImageFromは更新されません。

ループ内の他の関数への両方の呼び出しを削除すると、スクリプトが機能し始めます。それらが同期されていないことは知っていますが、すでに「親」が同期されている場合は同期されている必要がありますか?

filter.isOK()このように実装されます(他の関数はtrueまたはfalseを返します。hasRightColor含めた場合、コードは失敗します。計算が少し遅いためだと思います):

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

これはどのように起こりますか?Eclipseは、スローされた例外を表示しません(もちろん、これによりメソッドが終了します)。

複数のオブザーバーからリストの最新のコンテンツのみを取得するためのまったく異なるアプローチもあるかもしれません(プログラムが並行して実行されるため、各オブザーバーに複数回通知される可能性があります)。

4

1 に答える 1

0

わかりました、エラーはいくつかの邪悪なNullPointerExceptionであり、filter.isOk().

this.imageから parameter-passingに変更したため、IDE で確認できませんでしたが、ヘッダーimageを削除し、3 つの関数の最後のパラメーターを変更するのを忘れていました。private image

imageそのため、Eclipse は欠落についても未使用についても何も言いませんでしたthis.image

ついに。

于 2012-07-14T15:11:14.617 に答える