为什么即使我使用锁也会得到ConcurrentModificationException?

时间:2014-07-23 08:36:53

标签: java concurrency

这是我的班级:

public class AComplicatedclass {
    private List<Connection> activeConnections;
    private Lock lock = new ReentrantLock();          

    public void printConnections() {
        lock.lock();
        for(Connection c : activeConnections){ //exception happens here
            ...prints details about connection
            activeConnections.remove(c);
        }
        lock.unlock();
    }

    private class MyThread extends TimerTask {

        public void run() {
            lock.lock();
                ...can alter activeConnections....
            lock.unlock();
        }

    }
}

正如您所看到的,锁定对象应该可以防止由于对该共享阵列的并发访问而导致的问题。然而,当调用printConnections()方法时,我会在ConcurrentModificationException中获得for

为什么?根本没有并发修改!

3 个答案:

答案 0 :(得分:4)

很可能你在for循环中修改了你的集合。作为ConcurrentModificationException州的文件

  

例如,如果一个线程在使用失败快速迭代器迭代集合时直接修改了一个集合,那么迭代器将抛出此异常。

迭代器抛出异常的原因是无法再确定接下来要返回哪个元素。

因此,如果您想要修改收藏品,则需要切换为CopyOnWriteArrayList之类的内容,或明确使用Iterator

    Iterator<Connection> iterator = activeConenctions.iterator();
    while(iterator.hasNext()) {
        Connection c = iterator.next();
        if(/* what ever */) {
            iterator.remove();
        }
    }

答案 1 :(得分:1)

在foreach迭代期间编辑列表几乎总会导致ConcurrentModificationException,即使您的应用程序是单线程的。

如果需要在迭代期间删除项目,请使用迭代器:

final Iterator<Connection> iterator = activeConnections.iterator();
while(iterator.hasNext()) {
    final Connection connection = iterator.next();
    // ...prints details about connection
    iterator.remove();
}

答案 2 :(得分:0)

根据ConcurrentModificationException的Javadoc:

  

例如,一个线程通常不允许修改Collection而另一个线程正在迭代它。通常,在这些情况下,迭代的结果是不确定的。如果检测到此行为,某些Iterator实现(包括JRE提供的所有通用集合实现的实现)可能会选择抛出此异常。执行此操作的迭代器称为失败快速迭代器,因为它们快速而干净地失败,而不是在未来的未确定时间冒着任意的,非确定性行为的风险。

这与非同步访问无关。

有问题的操作的一些例子:

  • 从集合中删除迭代的当前元素,那个案例中的下一个元素是什么?
  • 删除了已经迭代过的一些元素,然后在集合中重新插入。迭代器是否应该在到达新位置时再次显示它?