2

現在、ExecutorService を使用して CopyOnWrite ArrayLists で文字列のバッチを並列処理するために送信しています。これらのリストを処理する Runnable タスクは、リストを反復処理し、各文字列で処理を行う必要があります。

通常の ArrayLists との同時実行の問題に遭遇した後、スレッドセーフであるため CopyOnWriteArrayLists を使用しようとしましたが、結果に一貫性がなくなりました。つまり、プログラムを実行するたびに異なる結果が得られます。これは、各 Runnable タスクが完全に反復される前に、arraylist の内容が何らかの方法で変更されたことを示唆しています。

public static class BatchRunnable implements Runnable {

    private CopyOnWriteArrayList<String> batch;

    BatchRunnable(CopyOnWriteArrayList<String> batch){
        this.batch = batch;
    }

    @Override
    public void run(){
        //iterate over batch and work with String elements
        //make no modifications to batch
    }
}
  • 実行可能なタスクは、配列リストに変更を加えず、リストを反復処理するだけで、リストの文字列要素を使用して処理を行います。

  • CopyOnWriteArrayList が変更される唯一の場所は、新しい Runnable タスクごとにインスタンス化されるときです。

バッチ処理の代わりに単一の文字列を渡していたとき、一貫性のある正しい結果が得られましたが、文字列 ArrayLists でバッチを使用し始めたとき、一貫性のない結果が得られました。安全。

どんな助けでも大歓迎です、ありがとう!

編集:これが私のバッチが構築されている場所です:

        Runnable worker = null;
        while((line = br.readLine()) != null) {
            recordBatch.add(line);
            if(recordBatch.size() == 100){
                worker = new BatchRunnable(recordBatch);
                executor.execute(worker);
                recordBatch.clear();
            }

        }           
        executor.shutdown();
        executor.awaitTermination(60,TimeUnit.SECONDS);  
4

4 に答える 4

2

あなたのwhileループを見てください:

while((line = br.readLine()) != null) {
        recordBatch.add(line);
        if(recordBatch.size() == 100){
            worker = new BatchRunnable(recordBatch);
            executor.execute(worker);
            recordBatch.clear();
        }

    }  

listすべてで同じへの参照を渡していますBatchRunnable。そのため、1 か所を変更するとすぐlistにすべての参照に反映されます。したがって、 を使用してリストをクリアするrecordBatch.clear()と、 にあるものも含めて、すべての参照のリストが空になりますBatchRunnable。そのため、一貫性のない結果が得られます。

リストの acopyを に渡す必要があります。recordBatchBatchRunnable

worker = new BatchRunnable(new ArrayList<String>(recordBatch));
于 2013-07-23T07:19:18.057 に答える
1

に渡した後、バッチをクリアしていBatchRunnableます。

 worker = new BatchRunnable(recordBatch);
 executor.execute(worker);
 recordBatch.clear(); // You clear all the list

そのため、executor はリストにあるものは何でも処理しますが、clear() 行に到達した場合 (exeuctor は別のスレッドで実行されるため、これはBatchRunnable終了前に発生する可能性があります)、リストは空になります (または次のバッチが含まれます!)。また、ワーカー バッチには一貫性のないリストが含まれます。

リストをワーカーに渡すと、コピーではなく参照が渡されます! したがって、バッチをコピーするか、バッチごとに新しいバッチを作成します。

 worker = new BatchRunnable(recordBatch);
 executor.execute(worker);
 recordBatch = new CopyOnWriteArrayList<String>();
于 2013-07-23T07:20:20.890 に答える
0

プレーン a で同時実行の問題が発生している場合、これは、反復ArrayList中に変更されたことを示しています。を aにBatchRunnable置き換えると、同時実行の問題が隠されるだけです。ArrayListCopyOnWriteArrayList

コードでは、BatchRunnable の作成中に (clear()およびadd()リストを変更しています。最初の実行可能ファイルが送信されると、リストの処理が開始されますが、それでも変更を続けます。

于 2013-07-23T07:19:24.787 に答える
0

イテレータを使用して要素を処理していると思います。イテレータは、イテレータが構築されたときのリストの状態のスナップショットを提供します。イテレータをトラバースしている間、同期は必要ありません。

したがって、あなたの場合、コンストラクターでイテレーターを取得するか、のコピーを作成する必要がありますCopyOnWriteArrayList

于 2013-07-23T07:15:51.620 に答える