Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/346.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 从HashMap中删除项会导致ConcurrentModificationException_Java_Arrays_Multithreading - Fatal编程技术网

Java 从HashMap中删除项会导致ConcurrentModificationException

Java 从HashMap中删除项会导致ConcurrentModificationException,java,arrays,multithreading,Java,Arrays,Multithreading,我有一个服务器应用程序,它有一个连接的ArrayList。这个程序使用多个线程。主线程每隔一段时间运行一个进程来检测关闭的连接,然后将它们从阵列中删除,以便对它们进行垃圾收集 这个过程如下: private void cullOtherProcessors() throws Exception { //log.log(Level.FINE,"XMLMessageReciever:cullOtherProcessors"); List<ConnectionAppInterfa

我有一个服务器应用程序,它有一个连接的ArrayList。这个程序使用多个线程。主线程每隔一段时间运行一个进程来检测关闭的连接,然后将它们从阵列中删除,以便对它们进行垃圾收集

这个过程如下:

private void cullOtherProcessors() throws Exception {
    //log.log(Level.FINE,"XMLMessageReciever:cullOtherProcessors");
    List<ConnectionAppInterface> toDel = new ArrayList<ConnectionAppInterface>();
    for (ConnectionAppInterface cur : m_OtherProcessors.keySet()) {
        if (cur!=null) {
            if (cur.isClosed()) {
                //Connection is closed - we could never send a message over it
                toDel.add(cur);
            }
        }
    }
    for (int c=0;c<toDel.size();c++) {
        log.log(Level.FINE,"**XMLMessageReciever:cullOtherProcessors - removing closed connection");
        m_OtherProcessors.remove(toDel.get(c));
    }
}
基本上,当我循环遍历ArrayList时,ArrayList发生了一些事情(可能是建立了另一个连接),导致nextNode抛出异常

我正在努力找出最好的方法来解决这个问题。我正在考虑简单地捕捉并忽略错误。任何遗漏的线程都将在下一个循环中被剔除。我建议的解决办法是:

private void cullOtherProcessors() throws Exception {
    //log.log(Level.FINE,"XMLMessageReciever:cullOtherProcessors");
    //m_OtherProcessors
    List<ConnectionAppInterface> toDel = new ArrayList<ConnectionAppInterface>();
    try {
        for (ConnectionAppInterface cur : m_OtherProcessors.keySet()) {
            if (cur!=null) {
                if (cur.isClosed()) {
                    //Connection is closed - we could never send a message over it
                    toDel.add(cur);
                }
            }
        }
    } catch (ConcurrentModificationException e) {
        log.log(Level.FINE,"**XMLMessageReciever:cullOtherProcessors - ConcurrentModificationException being ignored");
    }
    for (int c=0;c<toDel.size();c++) {
        log.log(Level.FINE,"**XMLMessageReciever:cullOtherProcessors - removing closed connection");
        m_OtherProcessors.remove(toDel.get(c));
    }
}
private void cullOtherProcessors()引发异常{
//log.log(Level.FINE,“xmlmessagereceiver:cullOtherProcessors”);
//m_其他处理器
List toDel=new ArrayList();
试一试{
对于(ConnectionAppInterface cur:m_OtherProcessors.keySet()){
如果(cur!=null){
if(cur.isClosed()){
//连接已关闭-我们无法通过它发送消息
toDel.add(cur);
}
}
}
}捕获(ConcurrentModificationException e){
log.log(Level.FINE,**xmlmessagereceiver:cullOtherProcessors-忽略ConcurrentModificationException);
}

对于(int c=0;c您最好使用synchronizedList:

您好,似乎您在对m_OtherProcessor进行循环时对其进行了修改

有两种方法比抓住我能想到的解释更好

1-如果m_OtherProcessors是一个小对象,而mem不是问题,那么您可以创建对象的本地副本,例如HashMap copy=new HashMap(m_OtherProcessors)。并使用此对象运行函数。(如果您希望避免复制过程中崩溃的可能性(这种可能性非常小),您可以在复制之前插入一个同步语句,例如synchronized(m_OtherProcessors){HashMap copy=new HashMap(m_OtherProcessors)})


2-您刚刚同步了方法或arrayList,这种同步将导致性能损失,但可靠性会提高。

在遍历/读取集合期间执行数据修改时,会导致并发修改异常

防止这种情况发生的最简单方法是:使用
迭代器
遍历
集合

迭代器iter=myArrayList.Iterator(); while(iter.hasNext()){ String str=iter.next(); 如果(某些条件) iter.remove(); }
一个
HashMap
不是线程安全的集合,这意味着您不应该与多个线程共享它,否则您将很难复制错误,如
ConcurrentModificationException
或由于

捕获
ConcurrentModificationException
显然是一种不好的做法,不应该这样做,因为它必须被视为
HashMap
的守护者,它会通知您是否同时修改了映射,这可能最终导致映射损坏和/或更糟的数据丢失


您更应该使用包中的线程安全集合。如果您需要线程安全的
Map
,您最好的选择是使用。

Uhm,忽略异常不是一件好事。您是否尝试提取此单元并用线程重现问题?我看到了一个争用条件,因为您正在阅读和编写相同的数据结构m_OtherProcessors而不同步创建m_OtherProcessors的位置??您确定错误与多线程相关吗?ConcurrentModificationException与线程无关。如果它是由于多线程而发生的,则仅捕获错误将无法避免不使用协处理器的后果nCCurrent data structure.m_OtherProcess是此类“Map m_OtherProcessors=new HashMap();”中的一个私有变量,当建立新连接时,会将项目放入该类中。可能重复感谢链接。我正在查看synchronizedMap。(我可能会将m_OtherProcessors转换为synchronizedMap)你仍然需要使用一个内在的锁来安全地迭代你的列表。这个列表对于方法调用来说是严格的局部性的。就线程安全而言,它不会带来任何问题。使用线程安全的实现不会有帮助。堆栈跟踪是关于映射的键集上的迭代。-1.我同意这篇文章,但是为什么你提到列表的线程安全性。这里的问题(我的意思是stacktrace)是映射的键集迭代的线程安全性。这里迭代的唯一列表是完全安全的(它严格地位于方法调用的本地),并且没有引起任何问题。所以我同意,但这看起来像“离题”对我来说?@GPI你是对的,我被这个问题弄糊涂了,修正了now@GPI我还修改了问题的标题,这就是为什么我感到困惑的原因,谢谢你的评论。也许你还应该提到,在并发修改问题之上,使用普通地图会带来可见性问题。因此,双重推荐使用并发地图andable。是的,完全正确。没有任何东西可以保证,在没有任何同步的规则映射下,线程所做的任何修改都会被其他线程看到。这不是纯粹的理论,它确实发生了:-)。这是正确的,但不完整。在多线程场景中,这不会有任何帮助:在并发访问的情况下,删除hashmap的派生迭代器是不安全的。您可能会得到陈旧的数据、不可见的数据、在无限循环中阻塞代码……各种各样的坏事都可能发生。此外,stacktrace没有提到问题所在在移除列表元素的过程中,但是在hashmap的迭代过程中。因此,这个答案,虽然陈述了一些真实的东西,但不适合这个问题。-1.在多线程场景中,OP可以使用synch
private void cullOtherProcessors() throws Exception {
    //log.log(Level.FINE,"XMLMessageReciever:cullOtherProcessors");
    //m_OtherProcessors
    List<ConnectionAppInterface> toDel = new ArrayList<ConnectionAppInterface>();
    try {
        for (ConnectionAppInterface cur : m_OtherProcessors.keySet()) {
            if (cur!=null) {
                if (cur.isClosed()) {
                    //Connection is closed - we could never send a message over it
                    toDel.add(cur);
                }
            }
        }
    } catch (ConcurrentModificationException e) {
        log.log(Level.FINE,"**XMLMessageReciever:cullOtherProcessors - ConcurrentModificationException being ignored");
    }
    for (int c=0;c<toDel.size();c++) {
        log.log(Level.FINE,"**XMLMessageReciever:cullOtherProcessors - removing closed connection");
        m_OtherProcessors.remove(toDel.get(c));
    }
}
Iterator<String> iter = myArrayList.iterator();

    while (iter.hasNext()) {
        String str = iter.next();

        if (someCondition)
            iter.remove();
    }