0

マルチスレッドを使用して文字列のリストをバッチで処理していますが、Runnable タスクがリストを反復処理して各文字列を処理しているときにこのエラーが発生します。

たとえば、コードは大まかに次の構造に従います。

public class RunnableTask implements Runnable {

private List<String> batch;

    RunnableTask(List<String> batch){
        this.batch = batch;
    }


    @Override
    public void run() {

        for(String record : batch){

            entry = record.split(",");
            m = regex.matcher(entry[7]);

            if (m.find() && m.group(3) != null){
                currentKey = m.group(3).trim();
                currentValue = Integer.parseInt(entry[4]);

                if ( resultMap.get(currentKey) == null ){
                    resultMap.put(currentKey, currentValue);
                } else {
                    resultMap.put(currentKey, resultMap.get(currentKey) + currentValue);
            }   
        }

    }
} 
}       

処理のためにこれらのバッチを渡すスレッドが「バッチ」を変更することはなく、バッチへの変更は for ループ内で行われません。この例外 ConcurrentModificationException は、反復中にリストを変更したことが原因であることを理解していますが、私が知る限り、それは起こっていません。足りないものはありますか?

どんな助けでも大歓迎です、

ありがとうございました!

UPDATE1:インスタンス変数はスレッドセーフではないようです。ArrayList の代わりに CopyOnWriteArrayList を使用しようとしましたが、一貫性のない結果を受け取りました。これは、リストが何らかの方法で変更される前に完全な反復が完了せず、すべての要素が処理されていないことを示唆しています。

UPDATE2:同期化および/または再入可能ロックを使用してループをロックすると、両方とも同じ例外が発生します。

Lists を Runnable タスクに渡し、新しいスレッドがそのリストで同時実行の問題を引き起こすことなく、それらのリストを反復処理する方法が必要です。

4

7 に答える 7

2

この例外 ConcurrentModificationException は、反復中にリストを変更したことが原因であることを理解していますが、私が知る限り、それは起こっていません

RunnableTask新しいスレッドを作成し、インスタンスへの参照を渡し、コンストラクターのパラメーターとして別のリストで初期化するとどうなるか考えてみてください。リスト参照を変更して、別のリストを指すようにしました。同時に、run()メソッド内の別のスレッドがlist任意の時点で を変更するとどうなるかを考えてみてください。これは、ある時点でスローしConcurrentModificationExceptionます。

インスタンス変数はスレッドセーフではありません。

于 2013-07-23T04:34:27.590 に答える
0

コードでこれを試してください:

public void run() {
    for(String record : new ArrayList(batch)){
        //do processing with record
    }
}

リストを処理するすべてのスレッドに一種の問題があります (リストはプロセス中に変更されますか?) が、提供しているコードではわかりにくいです

于 2013-07-23T04:33:29.627 に答える
0

明らかに、他の誰かがリストの内容を変更しています。これは、あなたが言及したコードの絵ではありません。( ConcurrentModificationException がリストに対して不平を言っているが、そうではないことが確実であり、実際にすべてのコードを RunnableTask に表示している場合batchresultMap

リストのコンテンツを更新している場所をコード内で検索して、同時に可能かどうかを確認してくださいRunnableTask

RunnableTask で単に同期するだけでは役に立ちません。リストへのすべてのアクセスを同期する必要がありますが、これは明らかに別の場所で行われています。

batchパフォーマンスが問題で、リストで同期できない(複数のRunnableTask同時実行を禁止する) 場合は、ReaderWriterLock の使用を検討してください。RunnableTask は読み取りロックを取得し、リスト更新ロジックは書き込みロックを取得します。

于 2013-07-24T02:49:05.853 に答える
0

List問題は、ソース構造を同時に変更する複数のスレッドによるものです。ソースリストを(サイズに応じて)新しいサブリストに分割し、そのリストをスレッドに渡すことをお勧めします。

ソースListに 100 個の要素があるとします。5つの同時スレッドを実行しています。

int index = 0;
List<TObject> tempList = new ArrayList<>();
for(TObject obj:srcList){
    if(i==(srcList.size()/numberOfthread)){
      RunnableTask task = new RunnableTask(tempList);
      tempList = new ArrayList<>();
    }else 
       tempList.add(obj);
}

この場合、元のリストは変更されません。

于 2013-07-23T04:38:21.247 に答える
0

あなたのフォローアップは、同じリストを複数回再利用しようとしていることを示しています。呼び出し元は、Runnable ごとに新しいリストを作成する必要があります。

于 2013-07-24T00:09:55.593 に答える