ConcurrentModificationException源码逐条解析

一家之言 姑妄言之 絮絮叨叨 不足为训

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源码所提供的信息也就到此为止了(ಥ_ಥ)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值