LinkedList中的ConcurrentModificationException

时间:2012-09-13 15:46:02

标签: java linked-list

我正在尝试设计一个将流程图转换为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;
}
}

7 个答案:

答案 0 :(得分:8)

在遍历列表时通常抛出ConcurrentModificationException,同时通常另一个线程甚至同一个循环尝试修改(添加/删除)列表的内容。

答案 1 :(得分:3)

为什么不使用 LinkedBlockingQueue http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/LinkedBlockingQueue.html

顺便说一句,这与同步无关。像这样的代码:

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

也会导致此异常。检查代码,以便在迭代时对列表进行可能的修改。

答案 2 :(得分:2)

使用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,因为这会将Queue与ThreadPool结合起来,并且更容易使用“后台”线程。

答案 3 :(得分:1)

当您遍历列表并在循环体中向其添加元素时,会发生这种情况。您可以在使用迭代器的remove()方法时安全地删除元素,但不能通过调用列表本身的任何remove()方法来删除元素。

解决方案是在迭代之前复制列表:

List<T> copy = new ArrayList<T>( list );
for( T e : copy ) {
    ... you can now modify "list" safely ...
}

答案 4 :(得分:1)

Java集合是快速失败的,这意味着所有现有迭代器在修改基础集合时变为无效 - 同步修改不会阻止列表使所有迭代器无效。

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

答案 5 :(得分:0)

List<X> myList = ....
List<X> myThreadSafeList = synchronizedList(myList);

synchronizedList(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());
}

答案 6 :(得分:0)

答案在这里:Why am I getting 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);
}