5

我正在尝试设计一种将流程图转换为 java 或任何其他代码的软件。但是我反复得到 ConcurrentModificationException.. 但我不能使用布尔值来防止 concurrentModification,因为对链表的访问发生在不同的地方。

因此,作为解决方案,我创建了以下适配器类。但是,它也会从下一个方法抛出相同的异常。有没有其他解决方案,或者如果可以,请让我知道如何修改我的代码......

非常感谢您...

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

使用 synchronizedList 或同步列表在迭代它时仍然必须在外部同步。

如果您使用 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

为什么不使用LinkedBlockingQueuehttp://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

当您遍历列表并在循环体中向其中添加元素时,就会发生这种情况。当您使用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 回答
1

Java 集合是快速失败的,这意味着所有现有的迭代器在底层集合被修改的那一刻变得无效 - 同步修改不会阻止列表使所有迭代器失效。

作为一种解决方法,您可以创建列表的副本以迭代或推迟修改直到迭代完成。要删除条目,您还可以使用 iterator.remove() 方法来保持迭代器本身有效。

于 2012-09-13T15:54:48.123 回答
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 回答