【问题标题】:ConcurrentModificationException in LinkedListLinkedList 中的 ConcurrentModificationException
【发布时间】:2012-09-13 15:46:02
【问题描述】:

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

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

非常感谢...

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;
}
}

【问题讨论】:

  • @SLaks “一旦你修复它就会起作用”必须是对 SO 最有帮助的评论。
  • @josefx:我的意思是他的问题是完全倒退。
  • 是的。这是正确的。在设计软件时,我没想到会出现任何多线程问题,因为我使用的是单线程。然而,使用paintComponent 时会意外出现多线程问题。然后作为解决方案,我尝试使用适配器。非常感谢

标签: java linked-list


【解决方案1】:

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

【讨论】:

  • 是的,在我的程序中,两个线程同时迭代,但是编码在不同的地方。因为我试图制作一个适配器。非常感谢……
  • 那么如何搜索列表中的项目并移除它们呢?
【解决方案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,因为这将队列与 ThreadPool 结合在一起,使使用“后台”线程更加容易。

【讨论】:

    【解决方案3】:

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

    顺便说一句,它不一定与同步有关。像这样的代码:

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

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

    【讨论】:

      【解决方案4】:

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

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

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

      【讨论】:

      • 这是最干净的解决方案。
      【解决方案5】:

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

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

      【讨论】:

        【解决方案6】:
        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());
        }
        

        【讨论】:

        • 不幸的是,这不起作用。我试图从 2 个计时器中修改列表,两者都带有 synchronized(list)。
        【解决方案7】:

        这里的答案: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);
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2016-12-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-09-23
          • 2016-07-25
          • 1970-01-01
          相关资源
          最近更新 更多