意外的ConcurrentModificationException

时间:2014-05-30 00:58:21

标签: java multithreading concurrency thread-safety concurrentmodification

不知道为什么我会收到这个例外。问题是有时在onClose之前调用closeAllOpenSessionsonClose正常运行,从_openSessions中移除指定的元素。但是,当我们调用closeAllSessions时,当我们尝试循环ConcurrentModificationException

时会生成_openSessions.

当我注释掉remove语句时,不会发生异常。考虑到这两个操作如何受同一个互斥锁的保护,我不确定为什么会发生这种情况。我错过了什么?

class B
{
    protected void onClose(Session session, List<WebSocketSessionStateful> openSessions) throws IOException
    {

        Iterator<WebSocketSessionStateful> openSessionsElements = openSessions.iterator();
        while(openSessionsElements.hasNext())
        {
            WebSocketSessionStateful openSession = openSessionsElements.next();
            if(session.equals(openSession.getSession()))
            {
                openSessionsElements.remove(); // comment me out to not throw exception
                return;
            }
        }
    }

    protected static void closeAllOpenSessions(List<WebSocketSessionStateful> openSessions) throws IOException
    {

        for(WebSocketSessionStateful openSession : openSessions) // exception generated here
        {
            openSession.getSession().close(new CloseReason(CloseReason.CloseCodes.GOING_AWAY, ""));
        }
    }
}

class A extends B
{
    private static final Object _endpointOperationMutex = new Object();

    private static final List<WebSocketSessionStateful> _openSessions = new ArrayList<WebSocketSessionStateful>();

    public void onClose(Session session, EndpointConfig config) throws IOException
    {
        synchronized (_endpointOperationMutex)
        {
            super.onClose(session, _openSessions);
        }
    }

    static void closeSessions() throws IOException
    {
        synchronized (_endpointOperationMutex)
        {
            WebSocketEndpointBase.closeAllOpenSessions(_openSessions);
        }
    }

}

1 个答案:

答案 0 :(得分:2)

closeAllOpenSesions()方法中,您将对openSessions集合进行迭代,并针对其中的每个元素调用close(),这当然会导致您的onClose() openSessions解雇方法。然后,您每次调用onClose()方法时都会迭代并从Iterator outerLoop = coll.iterator(); while (outerLoop.hasNext) { Iterator innerLoop = coll.iterator(); while (innerLoop.hasNext()){ innerLoop.remove(); //ConcurrentModificationException } } 中删除 - 这是您的并发修改的来源。

您可以更清楚地将问题概念化如下:

 for (Object o : coll)
     for (Object p : coll) 
         if (p.someBoolean()) remove(p); //ConcurrentModificationException

这与以下情况没有什么不同:

ConcurrentModificationException

您不能同时迭代同一个集合的两个迭代器。如果这样做,如果内部循环删除外部循环期望迭代的元素,则将抛出openSessions

乍一看,我不明白为什么你需要在B.onClose()内迭代B.onClose()。为什么closeAllOpenSessions()要负责关闭所有公开会话?不应该在{{1}}中完成吗?