fast-fail和fast-safe机制

fast-fail(快速失败)

在使用for循环遍历一个集合时,如果此时改变了集合的结构,如增、删,则会抛出ConcurrentModificationException异常。

原因:

  • 集合类中有一个modCount变量,在向集合中增加或者删除元素时都会修改这个变量的值;
  • 每当迭代器使用hasNext()/next()遍历下一个元素之前都会检测modCount变量和expectedModCount值是否相等;
  • 如果相等的话就返回遍历,否则抛出异常,终止遍历。

具体代码如下:

final void checkForComodification() {  
    if (modCount != expectedModCount) // 1 
        throw new ConcurrentModificationException();  
} 

需要注意的是,在序号1处,异常的抛出条件时检测到modCount != expectedmodCount 这个条件。如果集合发生变化时修改modCount值, 刚好有设置为了expectedmodCount值, 则异常不会抛出。比如删除了数据,再添加一条数据。所以不能依赖于这个异常是否抛出而进行并发操作的编程, 这个异常只建议检测并发修改的bug。

使用场景 :

java.util包下的集合类都是快速失败机制的, 不能在多线程下发生并发修改(迭代过程中被修改).
fail-safe ( 安全失败 )

采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先copy原有集合内容,在拷贝的集合上进行遍历。

原理:

由于迭代时是对原集合的拷贝的值进行遍历,所以在遍历过程中对原集合所作的修改并不能被迭代器检测到,所以不会出发ConcurrentModificationException。

缺点:

基于拷贝内容的优点是避免了ConcurrentModificationException,但同样地, 迭代器并不能访问到修改后的内容。 (简单来说就是, 迭代器遍历的是开始遍历那一刻拿到的集合拷贝,在遍历期间原集合发生的修改迭代器是不知道的)

使用场景:

java.util.concurrent包下的容器都是安全失败的,可以在多线程下并发使用,并发修改。

原文地址:https://www.cnblogs.com/reecelin/p/13380695.html