为了账号安全,请及时绑定邮箱和手机立即绑定

为什么抛出ConcurrentModificationException以及如何调试它

为什么抛出ConcurrentModificationException以及如何调试它

慕标琳琳 2019-06-14 10:39:06
为什么抛出ConcurrentModificationException以及如何调试它我用的是Collection(A)HashMapJPA间接使用,但显然代码会随机抛出一个ConcurrentModificationException..是什么导致了这一问题,我如何解决这个问题?也许是通过一些同步?下面是完整的堆栈跟踪:Exception in thread "pool-1-thread-1" java.util.ConcurrentModificationException         at java.util.HashMap$HashIterator.nextEntry(Unknown Source)         at java.util.HashMap$ValueIterator.next(Unknown Source)         at org.hibernate.collection.AbstractPersistentCollection$IteratorProxy.next(AbstractPersistentCollection.java:555)         at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:296)         at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:242)         at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:219)         at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)         at org.hibernate.engine.Cascade.cascade(Cascade.java:130)
查看完整描述

3 回答

?
隔江千里

TA贡献1906条经验 获得超10个赞

这不是同步问题。如果正在迭代的基础集合被Iterator本身以外的任何东西修改,就会发生这种情况。

Iterator it = map.entrySet().iterator();while (it.hasNext()){
   Entry item = it.next();
   map.remove(item.getKey());}

这将在第二次调用它.hasNext()时抛出一个ConcurrentModificationException。

正确的方法是

   Iterator it = map.entrySet().iterator();
   while (it.hasNext())
   {
      Entry item = it.next();
      it.remove();
   }

假设此迭代器支持Remove()操作。


查看完整回答
反对 回复 2019-06-14
?
慕桂英3389331

TA贡献2036条经验 获得超8个赞

尝试使用ConcurrentHashMap而不是普通的HashMap


查看完整回答
反对 回复 2019-06-14
?
侃侃无极

TA贡献2051条经验 获得超10个赞

修改aCollection当迭代的时候Collection使用Iterator不允许大部分Collection上课。Java库调用试图修改Collection虽然迭代它是一个“并发修改”,但不幸的是,这表明唯一可能的原因是由多个线程同时进行修改,但事实并非如此。只使用一个线程,就可以为Collection(使用Collection.iterator(),或增强型for环路),开始迭代(使用Iterator.next(),或等效地进入增强体的主体for循环),修改Collection,然后继续迭代。

为了帮助程序员,一些的实现Collection尝试若要检测错误的并发修改,请抛出ConcurrentModificationException如果他们发现了。但是,保证检测到所有并发的修改通常是不可能的,也是不可行的。如此错误地使用Collection并不总是导致抛出ConcurrentModificationException.

.的文件ConcurrentModificationException说:

此异常可能由检测到对象的并发修改的方法引发,而这种修改是不允许的.

请注意,此异常并不总是指示对象已被不同线程并发修改。如果单个线程发出一系列违反对象契约的方法调用,该对象可能会抛出此异常.

请注意,通常情况下,不能保证快速失败的行为在存在不同步并发修改的情况下提供任何硬的保证。失败操作抛出ConcurrentModificationException在尽最大努力的基础上。

请注意

的文件HashSetHashMapTreeSetArrayList课程上说:

[直接或间接地从该类返回的迭代器]失败快速:如果[集合]在迭代器创建后的任何时候被修改,则除通过迭代器自身的Remove方法外,以任何方式修改Iterator抛出ConcurrentModificationException..因此,在并发修改的情况下,迭代器会迅速而干净地失败,而不是在未来某个未定的时间冒着任意的、不确定的行为的风险。

请注意,迭代器的快速失败行为不能保证,一般来说,在不同步并发修改的情况下不可能提供任何硬的保证。失败快速迭代器抛出ConcurrentModificationException在尽最大努力的基础上。因此,编写一个依赖于此异常的程序是错误的:迭代器的抗故障行为应该仅用于检测bug。.

请再次注意,这种行为“不能保证”,而且仅仅是“在尽最大努力的基础上”。

的几种方法的文档化。Map接口说明如下:

非并发实现应该覆盖此方法,并在最大努力的基础上抛出ConcurrentModificationException如果检测到映射函数在计算期间修改此映射。并发实现应该覆盖此方法,并在最大努力的基础上抛出IllegalStateException如果检测到映射函数在计算期间修改此映射,则计算将永远不会完成。

请再次注意,检测只需要“尽最大努力的基础”,并且ConcurrentModificationException显式地建议只用于非并发(非线程安全)类。

调试ConcurrentModificationException

因此,当您看到堆栈跟踪是由于ConcurrentModificationException,您不能立即假定原因是不安全的多线程访问Collection..你必须检查堆栈跟踪决定哪一类Collection抛出异常(类的方法将直接或间接抛出它),其中Collection对象。然后,您必须从可以修改对象的位置进行检查。

  • 最常见的原因是修改

    Collection

    在增强的范围内

    for

    循环在

    Collection

    ..仅仅因为你没有看到

    Iterator

    对象在您的源代码中并不意味着没有

    Iterator

    那里!幸运的是,有一个错误的说法

    for

    循环通常在堆栈跟踪中,因此跟踪错误通常很容易。
  • 更棘手的情况是,当您的代码在引用中传递到

    Collection

    对象。请注意

    不可修改

    收藏的视图(如由

    Collections.unmodifiableList()

    )保留对可修改集合的引用,因此

    对“不可修改”集合的迭代可以引发异常。

    (修改已在其他地方完成)。其他

    意见

    你的

    Collection

    ,如

    子列表Map条目集

    Map密钥集

    还保留对原始(可修改)的引用

    Collection

    ..这可能是一个问题,即使是线程安全。

    Collection

    ,如

    CopyOnWriteList

    不要假设线程安全(并发)集合永远不会抛出异常。
  • 哪些操作可以修改

    Collection

    在某些情况下可能是意外的。例如,

    LinkedHashMap.get()修改其集合.

  • 最困难的情况是例外

    由多个线程并发修改造成的。

防止并发修改错误的编程

如果可能,将所有引用限制在Collection对象,因此它更容易防止并发修改。使.Collection a private对象或局部变量,并且不返回对Collection或者方法中的迭代器。这样就容易得多了。在那里Collection可以修改。如果Collection将由多个线程使用,则确保线程访问Collection只有适当的同步和锁定。


查看完整回答
反对 回复 2019-06-14
  • 3 回答
  • 0 关注
  • 1656 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号