一家之言 姑妄言之 絮絮叨叨 不足为训
ConcurrentModificationException类注释翻译:
当不允许修改时,已经检测到对象并发修改的方法可能会抛出此异常。
例如,当一个线程在集合上迭代时,通常不允许另一个线程修改集合。一般来说,迭代的结果在这种情况下是没有定义的。如果检测到上述行为,某些迭代器实现(包括JRE提供的所有通用集合实现)可能会选择抛出此异常。这样做的迭代器被称为故障快速fail-fast
迭代器,因为它们快速而干净地失败了,而不是在将来某个不确定的时间冒着任意的、不确定的行为的风险。
请注意,此异常并不总是表示对象已被其他线程并发修改。如果单个线程发出的一系列方法调用违反了对象的契约,则对象可能会抛出此异常。例如,如果线程在使用故障快速fail-fast
迭代器遍历集合时直接修改集合,迭代器将抛出此异常。
注意,快速故障行为fail-fast
不能得到保证,因为通常来说,在非同步并发修改的情况下,不可能做出任何严格的保证。快速故障操作会在最大努力的基础上抛出ConcurrentModificationException异常。因此,编写一个依赖于这个异常来保证其正确性的程序是错误的:ConcurrentModificationException应该只用于检测bug。
笔者废话:
其实这个异常类的注释已经写得很不错了,但是由于笔者翻译的问题(不敢加入个人色彩太多以避免文意曲解)导致可能看着有些拗口。
实际上这个异常就是文案上的含义:
1. 多线程时,发生并发修改时,这个异常会抛出;
2. 单线程时,在遍历过程中修改了集合,这个异常也会抛出;
3. 我们对这个异常是否可以正确抛出是不做严格保证的。因为这种机制是谁都不可能严格地去说,对,这里一定会抛出这个异常。所以,这里是非常不建议我们的程序依赖这个fail-fast机制来编写程序。它最佳的用处也就是检测bug,而不是依此来进行复杂业务处理。
ConcurrentModificationException类信息:
public class ConcurrentModificationException extends RuntimeException
我们可以清楚的看到,ConcurrentModificationException 一个是继承自RuntimeException类的异常类。
ConcurrentModificationException静态变量信息:
/* 序列化版本编号 */
private static final long serialVersionUID = -3666751008965953603L;
我们来看ConcurrentModificationException的静态变量信息。
这里的静态变量信息唯独就是生成了一个序列化版本编号。这个类的整体集成方式是这样的:ConcurrentModificationException
->RuntimeException
->Exception
->Throwable
。而Throwable
实现了java.io.Serializable
接口。所以这里有一个序列化版本编号也不足为奇。
ConcurrentModificationException构造函数信息:
/**
* 构造一个没有详细信息的ConcurrentModificationException异常。
*/
public ConcurrentModificationException() {
}
/**
* 构造一个指定详细信息的ConcurrentModificationException异常。
* @param message 与此异常相关的详细信息。
*/
public ConcurrentModificationException(String message) {
super(message);
}
/**
* 构造一个带有指定原因和详细信息
* (cause==null ? null : cause.toString())
* 的ConcurrentModificationException异常(其中通常包含类和指定
* 原因的详细信息)。
* @param cause 错误原因(该原因将被Throwable.getCause()方法
* 保存,供以后检索)(允许空值,并指示原因不存在或未知。)
* @since 1.7
*/
public ConcurrentModificationException(Throwable cause) {
super(cause);
}
/**
* 构造一个带有指定原因和详细信息的ConcurrentModificationException异常
* 请注意,与cause相关的详细信息不会自动合并到此异常的详细信息中。
* @param message 详细信息(它被保存起来供以后使用
* Throwable.getMessage()方法检索)。
* @param cause 原因(该原因将被Throwable.getCause()方法保存,供以后检
* 索)。(允许为空值,并指示原因不存在或未知。)
* @since 1.7
*/
public ConcurrentModificationException(String message, Throwable cause) {
super(message, cause);
}
其实到这里你会发现整个类就已经结束了。对的,这个异常类的所有方法都是其本身的构造方法,是没有其他业务方法的。所以这里一连展示了其4个构造方法,有参的,无参的。同时,这里也一并对其介绍而不需要一个一个的讲解。
为什么不需要一个一个讲解呢,我们仔细从代码体得知,这些构造方法无不在(除了无参构造器)都在调用其父类的构造方法。而这个父类你都可以追踪到它的祖宗辈儿Throwable
类。
我们整体来看这四个构造方法,其中第二个构造函数是第一个构造函数的扩展体,第四个构造函数是第三个构造函数的扩展体(这两个函数都是从Java1.7才开始有的)。
那么,其实我们去搜寻现有的Java1.8源码包,也就第一无参构造器和第三有参构造器是被引用的。其中第一无参构造器被引用100次,第三有参构造器仅被引用4次(其中Map
接口引用三次,DirectoryIteratorException
异常类引用一次)。整个异常类都是在进行错误信息的收集。最主要的关注点其实还是它是如何被触发的,不过它的触发时机已经在上面简述过了,我们只需简单的知道这个类的大体构造就可以了~
其实到这里我们ConcurrentModificationException
到此全部解析完毕了,可能整篇文章显得无所重要,其实不然。因为这整个专题的部分源码分析都会涉及到此异常。这个解析已经是这个类可以提供的全部信息了,其他你想要的解析其实是需要具体到引用其类的源码上的。
ConcurrentModificationException
源码所提供的信息也就到此为止了(ಥ_ಥ)。