【问题标题】:Getting java.util.LinkedList$ListItr.checkForComodification exception while using iterators?使用迭代器时获取 java.util.LinkedList$ListItr.checkForComodification 异常?
【发布时间】:2015-01-18 11:26:48
【问题描述】:

我在实现Runnable 的类中使用listIterator() 访问和删除LinkedList 中的项目我还在程序的其他部分同时修改此列表的值。

我在这部分代码中使用listIterator() 的地方是我从这个函数调用中得到ConcurrentModificationException

java.util.LinkedList$ListItr.checkForComodification

为什么会出现这种情况以及如何预防?

    @Override
    public void run()
    {

        while(true)
        {
            itr = nodeAttributes.listIterator();

            while (itr.hasNext()) 
            {
                System.out.println("enterred");
                nodeAttribute nA = (nodeAttribute) itr.next();
                //System.out.println("for");
                 if(!nA.isMoving && !nA.moveQueue.isEmpty())
                 {
                     if(animator != null)
                         animator.stop();

                     animator = (Animator) nA.moveQueue.poll();
                     //itr.remove();
                     animator.start();
                     nA.isMoving = true;
                     System.out.print( "animator");
                 }
            }
            System.out.println( "looping");

        }
    }

【问题讨论】:

  • 你有类似堆栈跟踪的东西,所以你知道它出现在哪一行吗?
  • 不,我不知道它发生在哪一行。
  • 您是否尝试过使用 try catch 来处理您的内部 for 循环的内容?

标签: java multithreading concurrency iterator


【解决方案1】:

您的帖子没有问题,只是一个声明。但是,您描述的是预期的行为。来自the docs

此类的迭代器和 listIterator 方法返回的迭代器是快速失败的:如果在创建迭代器后的任何时间对列表进行结构修改,除了通过迭代器自己的删除或添加方法之外的任何方式,迭代器将抛出ConcurrentModificationException。

因此,为了防止这种情况发生,您需要在读者迭代的同时防止作者进行修改。使用Collections.synchronizedList 方法。所有访问(读者和作者)都应该遵循这种模式:

// store a single synchronized list reference for all access to use
nodeAttributes = Collections.synchronizedList(theLinkedList);

然后所有的读者和作者都应该使用synchronized (list) 块。

// Readers might do:
synchronized (list) {
  itr = nodeAttributes.listIterator();
  while (i.hasNext())
      ... do stuff ...
}

那些没有迭代操作的线程可以只使用来自Collections.synchronizedList的返回对象的“原子”方法,例如add。这些方法在幕后使用了一个同步块,所以它们只是一种简写,当另一个线程在同步块中时它们仍然会阻塞线程。

处理并发读写器的方法有很多很多。

  1. 上面是一个,但它可能会在每个迭代器执行它的东西时长时间锁定其他线程。
  2. 另一种是将列表复制到数组中(在同步部分内),然后在锁外读取数组。
  3. 还有一种方法是使用ReadWriteLock

还有更多选项,全部取决于您的具体用例。

【讨论】:

  • 将内循环放入try-catch 语句后,不再发生异常。我很困惑为什么代码行为奇怪?还是不再发生异常是偶然的?
  • @AliNfr 是的,这可能是机会。您违反了黄金法则:不要同时在两个线程中读取和写入未同步的列表。
  • 如果我只是通过捕获它来忽略异常会发生什么?似乎没有什么不好的事情发生。
  • @AliNfr 可能会发生坏事,而您只是隐藏了它们的后果:您的读取迭代器不会完成对整个列表的迭代。只有一个有效的解决方案:同步所有线程的列表访问。
  • 我是否应该更改正在修改和读取列表的代码的另一部分(这部分的方式相同)? , 因为我仍然遇到异常。
猜你喜欢
  • 2020-01-15
  • 2013-09-06
  • 1970-01-01
  • 2015-09-03
  • 1970-01-01
  • 1970-01-01
  • 2020-09-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多