ConcurrentModificationException

最近在写android程序的过程中,对容器ArrayList操作的时候,碰到了java.util.ConcurrentModificationException异常,是在遍历一个容器的时候,删除容器里面的元素:

public static void exit(){
   for (Activity activity : activityList){
       activity.finish();
       activityList.remove(activity);
   }
}
  • 官方文档中的说法是这样的:
    • This exception may be thrown by methods that have detected concurrent modification of an object when such modification is not permissible.(concurrent是同时发生,大概意思是当一个object被同时修改的时候,而且该修改是不允许的,就会报这个异常)
    • For example, it is not generally permissible for one thread to modify a Collection while another thread is iterating over it(一个线程在修改容器,而另外一个线程在遍历这个容器,这样是不允许的). In general, the results of the iteration are undefined under these circumstances. (这样做的会发生不确定的结果)Some Iterator implementations (including those of all the general purpose collection implementations provided by the JRE) may choose to throw this exception if this behavior is detected. (有一些容器的迭代器检测到这样的行为,就会抛出这个异常)Iterators that do this are known as fail-fast iterators, as they fail quickly and cleanly, rather that risking arbitrary, non-deterministic behavior at an undetermined time in the future.(这种称作fail-fast迭代器,它们失效的很快而且很干净利落而不是愿意冒发生不确定行为的危险, 大概就是说, 遇到这种情况迭代器自己直接就把自己给失效了)
    • Note that this exception does not always indicate that an object has been concurrently modified by a different thread. (这种异常不总是在一个object被不同线程同时修改时抛出, 即不是总是抛出这个异常)If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception. For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will throw this exception.(当一个线程对一个容器操作的时候, 例如用fail-fast迭代器边遍历边修改这个容器,就是抛出这个异常)
    • Note that fail-fast behavior cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast operations throwConcurrentModificationException on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: ConcurrentModificationException should be used only to detect bugs.
  • 解决方案通常是使用Iterator的remove方法,我对几个常用的集合类都试了,是可以的。这样做的原理在于:
  • Iterator 是工作在一个独立的线程中,并且拥有一个 mutex 锁。 Iterator 被创建之后会建立一个指向原来对象的单链索引表,当原来的对象数量发生变化时,这个索引表的内容不会同步改变,所以当索引指针往后移动的时候就找不到要迭代的对象,所以按照 fail-fast 原则 Iterator 会马上抛出 java.util.ConcurrentModificationException 异常。
  • 所以 Iterator 在工作的时候是不允许被迭代的对象被改变的。但你可以使用 Iterator 本身的方法 remove() 来删除对象, Iterator.remove() 方法会在删除当前迭代对象的同时维护索引的一致性。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Coding01

轻轻玩转 Laravel Helpers 函数

在使用 Laravel 函数时,我们都避免不了使用其提供的各种各样的全局函数,也称为辅助函数。

27310
来自专栏技术点滴

编译器构造

编译器构造 一、 编译器简介 前面谈到静态链接器构造的基本流程,最后提到所构造的链接器若要能正常工作的前提是需要构造一个能生成符合链接器输入文件格式的编译器,本...

25980
来自专栏linux运维学习

linux学习第六十五篇:for循环,while循环, break跳出循环,continue结束本次循环

for循环 语法:for 变量名 in 条件; do …; done for循环会以空格作为分隔符 案例1 #!/bin/bash sum=0 for i ...

298100
来自专栏专注 Java 基础分享

深入理解Struts2----类型转换

     之前的一系列文章主要介绍了有关Struts2的一些基本用法和部分的简单原理,但是始终没有介绍有关拦截器的相关内容,从本篇开始我们将从另一个角度去深入理...

23290
来自专栏orientlu

C 实现 哈夫曼编码

哈夫曼编码是一种用于数据压缩的无损熵编码,根据压缩数据符号出现频率大小进行编码, 出现频率越高,编码后占bit 越少的变长编码。(其他详细介绍见参考)

28430
来自专栏游戏开发那些事

【游戏开发】小白学Lua——从Lua查找表元素的过程看元表、元方法

在上篇博客中,我们简单地学习了一下Lua的基本语法。其实在Lua中有一个还有一个叫元表的概念,不得不着重地探讨一下。元表在实际地开发中,也是会被极大程度地所使用...

18530
来自专栏计算机视觉与深度学习基础

Leetcode 138 Copy List with Random Pointer

A linked list is given such that each node contains an additional random pointe...

199100
来自专栏Java技术栈

干货:排名前 16 的 Java 工具类!

在Java中,工具类定义了一组公共方法,这篇文章将介绍Java中使用最频繁及最通用的Java工具类。以下工具类、方法按使用流行度排名,参考数据来源于Github...

52250
来自专栏微信公众号:Java团长

Java开发中对Redis的基本操作总结

想要在 Java 中使用 Redis,我们首先需要安装 redis 服务及 Java redis 驱动。

3.6K50
来自专栏从流域到海域

《笨办法学Python》 第3课手记

《笨办法学python》第3课手记 本节课介绍运算符,如果你有C语言的基础的话很简单,运算符跟C语言都一样,优先级也一样。出现小数会四舍五入。但逻辑判断时,C语...

20280

扫码关注云+社区

领取腾讯云代金券