【问题标题】:java ConcurrentModificationException even with synchronizedjava ConcurrentModificationException 即使与同步
【发布时间】:2013-10-03 16:48:58
【问题描述】:

之前已经发布过类似的问题,但这种情况有所不同 - 静态使用可能会使问题复杂化。 只是想看看是否有人对如何处理这个问题有想法。 即使我在修改它的两个块周围的列表上使用同步,我也会得到 ConcurrentModificationException。

public class Foo {
   public void register() {
       FooManager.addFoo(this);
   }
}

public class ABC1 {
   static Foo myfoo;
   static {
     myfoo = new Foo();
     myfoo.register();
   }
}

(我有多个类似的类 ABC2、ABC3)

public class FooManager {
   static ArrayList<Foo> m_globalFoos;
   static ABC1 m_abc;
   static {
     m_globalFoos = new ArrayList<Foo>();
     m_abc = new ABC1();
   }


   public static void addFoo(Foo foo) {
     synchronized(m_globalFoos) { // SYNC
         m_globalFoos.add(foo);
      }
   }

    public static void showFoos() {
        synchronized(m_globalFoos) { //SYNC
            for (Foo foo : m_globalFoos) {
                     foo.print();
            }
    }
}

我声明 ABC1、ABC2、ABC3 等超过 1 个线程功能。 在我的主程序中,第一行

main() {
    FooManager.showFoos();

异常详情:

Exception in thread "main" java.util.ConcurrentModificationException
        at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
        at java.util.AbstractList$Itr.next(AbstractList.java:343)
        at com.mytest.FooManager.showFoos(FooManager.java:78)
        at com.mytest.FooTest.main(FooTest.java:109)

【问题讨论】:

  • 这里只有1个线程吗?您无法仅使用单个线程获得并发修改。要了解这实际上是如何发生的,我需要了解您何时以及如何制作线程。
  • 当然可以,尝试循环遍历 Set 并从循环中删除项目(不使用正确的 iterator.remove 方法)
  • @JasonNichols 很公平,但至少在这种情况下不是
  • @Cruncher - 实际上,您可以通过一个线程获得 ConcurrentModificationException。事实上,这是最有可能发生的情况(也是最常见的错误)。
  • 显示完整的异常堆栈跟踪。

标签: java synchronized


【解决方案1】:

实际上,您的内在锁在您正在迭代的 ArrayList 上。看起来 FooHandler 或 print() 函数都有一个对您的 ArrayList 的引用,该 ArrayList 试图向其中添加/删除内容。根据 JAVADOC 的说法,这个异常可能是因为同一个线程或不同的线程而发生的,但并不总是不同的线程。因此,如果您有某种操作试图修改您的 Arraylist,则可能会发生此错误。

尝试使用快速失败的迭代器来避免此类错误。

【讨论】:

  • 我在这里展示的是唯一使用 Arraylist 的两个地方。没有其他修改发生。无论如何,我已经在两个块周围同步了。
【解决方案2】:

您没有包含很多代码,但我的猜测是 foo.print 正在做的事情最终会调用 addFoo (几乎可以保证 CME 的堆栈跟踪同时具有 showFoosaddFoo 在里面)。 100 次中有 99 次 ConcurrentModificationException 是由单个线程引起的,而不是由多个线程引起的(尽管名称令人困惑)。

(是的,这个“错误”与所有其他关于 CME 的 SO 帖子相同)。

【讨论】:

  • 我们也没有这个代码:FooHandler.addFoo(this);,而是FooManager.addFoo
  • @porfiriopartida - FooHandler 和 FooManager 可能是同一个类,只是打错了。
  • 是的 - 修正了错字。 print dosent 做任何事情 - 只是打印出来 - 没有它调用 addFoo.
  • @excalibur - 除了显示的 2 种方法之外,还有其他访问 m_globalFoos 的权限吗?
  • @excalibur - 这些方法中的任何一种都重新分配 m_globalFoos 吗?
【解决方案3】:

您可能与其他类一起工作,在您的 main() 中您使用 FooHandler,但您没有在您的问题中提供它的代码...如果不是,请在此处发布异常的堆栈跟踪。

【讨论】:

  • 抱歉打错了...它是 FooManager,而不是 FooHandler..它是更大代码库的一部分,所以我删掉了需要的内容
猜你喜欢
  • 2013-02-26
  • 2019-12-27
  • 2014-09-26
  • 2010-12-11
  • 2014-06-19
  • 1970-01-01
  • 1970-01-01
  • 2018-05-18
  • 1970-01-01
相关资源
最近更新 更多