5

フローチャートをJavaやその他のコードに変換するソフトウェアを設計しようとしています。ただし、ConcurrentModificationExceptionが繰り返し発生します。ただし、リンクリストへのアクセスはさまざまな場所で発生するため、ブール値を使用してconcurrentModificationを防ぐことはできません。

そこで、解決策として、以下のアダプタクラスを作成しました。ただし、次のメソッドからも同じ例外がスローされます。他の解決策はありますか、または可能であれば、plzは私のコードを変更する方法を教えてくれます...

どうもありがとうございます...

import java.util.Iterator;
import java.util.LinkedList;

public class LinkedListAdapter<T> extends LinkedList<T>{

@Override
public boolean add(T t){

    boolean b;

    synchronized(this){
        b = super.add(t);
    }

    return b;
}

@Override
public T remove(){

    T t;

    synchronized(this){
        t = super.remove();
    }

    return t;
}

@Override
public Iterator<T> iterator(){

    final LinkedListAdapter<T> adap = this;

    return 
        new Iterator<T>(){

        private Iterator<T> iter;

        {
            synchronized(adap){
                iter = LinkedListAdapter.this.getIterator();
            }
        }

        @Override
        public boolean hasNext() {

            boolean b;

            synchronized(adap){
                b = iter.hasNext();
            }

            return b;
        }

        @Override
        public T next() {

            T t;

            synchronized(adap){
                t = iter.next();
            }

            return t;
        }

        @Override
        public void remove() {
            throw new UnsupportedOperationException();
        }
    };
}

protected Iterator<T> getIterator() {

    Iterator<T> iter;

    synchronized(this){
        iter = super.iterator();
    }

    return iter;
}
}
4

7 に答える 7

12

これConcurrentModificationExceptionは通常、リストを反復処理するときにスローされ、同時に通常は別のスレッドまたは同じループでさえ、リストの内容を変更(追加/削除)しようとします。

于 2012-09-13T15:48:50.843 に答える
4

同期リストまたは同期リストを使用する場合は、それを反復処理するときに外部で同期する必要があります。

ConcurrentLinkedQueueを使用する場合、これらの問題は発生しません。

Queue<Task> tasks = new ConcurrentLinkedQueue<Task>();
tasks.add(task); // thread safe
tasks.remove(task2); // thread safe

for(Task t: tasks) // can iterate without a CME.

注:別のスレッドでキューを使用している場合は、ExecutorServiceを使用することをお勧めします。これにより、キューとThreadPoolが組み合わされ、「バックグラウンド」スレッドでの作業がはるかに簡単になります。

于 2012-09-13T15:57:43.007 に答える
3

LinkedBlockingQueueを使用してみませんか?http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/LinkedBlockingQueue.html

ところで、それは必ずしも同期とは関係ありません。このようなコード:

for(Value v : valuesList){
    valueslist.add(new Value());
}

この例外も発生します。リストが繰り返されているときに、リストが変更される可能性があるかどうかコードを確認してください。

于 2012-09-13T15:53:53.663 に答える
1

Javaコレクションはフェイルファストです。つまり、基になるコレクションが変更された瞬間に既存のすべてのイテレーターが無効になります。変更を同期しても、リストがすべてのイテレーターを無効にするのを防ぐことはできません。

回避策として、リストのコピーを作成して、反復を繰り返すか、反復が終了するまで変更を延期することができます。エントリを削除するには、イテレータ自体を有効に保つiterator.remove()メソッドを使用することもできます。

于 2012-09-13T15:54:48.123 に答える
1

これは、リストを繰り返し処理し、ループの本体でリストに要素を追加したときに発生します。remove()イテレータのメソッドを使用する場合は要素を安全に削除できますがremove()、リスト自体のメソッドを呼び出すことはできません。

解決策は、リストを繰り返す前にリストをコピーすることです。

List<T> copy = new ArrayList<T>( list );
for( T e : copy ) {
    ... you can now modify "list" safely ...
}
于 2012-09-13T15:53:07.160 に答える
0
List<X> myList = ....
List<X> myThreadSafeList = synchronizedList(myList);

同期リスト(myList)

JavaDocの次のステートメントに注意してください。

返されたリストを反復処理するときは、ユーザーが手動でリストを同期する必要があります。

List list = Collections.synchronizedList(new ArrayList());
    ...
synchronized(list) {
    Iterator i = list.iterator(); // Must be in synchronized block
  while (i.hasNext())
      foo(i.next());
}
于 2012-09-13T15:49:56.190 に答える
0

ここでの答え:なぜjava.util.ConcurrentModificationExceptionが発生するのですか?とても助かりました。

誰かがこのエラーを修正しようとしている場合に備えて、ここにコピーして貼り付けます。

リストを反復処理する場合、リストからアイテムを削除することはできません。これを行うと、例外が発生します。

行う:

int size = list.size();
for (int i = 0 ; i< size ; i++) {
   list.add(0,"art");
   list.remove(6);
   System.out.println(list);
}
于 2016-02-22T07:36:37.253 に答える