原理:迭代器在遍历时直接访问集合中的内容,并且在遍历过程 中 使 ⽤⼀个 modCount 变量。
集合在被 遍历期 间如果内容发⽣ 变 化 ,就会改变 modCount 的值。每当迭代器使⽤
hashNext()/next()遍历下⼀个元素之 前,都会检测modCount变量是否为expectedmodCount
值,是的话 就 返回遍历;否则抛出 异常, 终⽌遍历。
注意:这⾥异常的 抛 出 条件是 检测到 modCount! =expectedmodCount 这个条件。如果集合发
⽣ 变 化 时 修 改 modCount值 刚 好 又设置为了expectedmodCount值,则异常不会抛 出。因此,不能
依赖于这个异常是否抛 出 ⽽进⾏ 并 发 操 作的编程,这个异常只 建议⽤于检测并发 修 改的bug。
场景: java.util包 下的集合类都是快速失败的,不能在多线程下发⽣并发 修 改(迭代过 程 中 被修
改),⽐如ArrayList 类。
安全失败(fail—safe)
采 ⽤ 安全失败机 制 的集合容器 ,在遍历时不是直接在集合内容上访问的,⽽ 是先复制 原有集合内
容,在拷贝的集合上进 ⾏遍历。
原理:由 于 迭代时是对原集合的拷贝进⾏遍历,所以在遍历过程 中对原集合所作的修 改 并 不能被迭
代器检测到,所以不会触发Concurrent Modification Exception。
缺 点:基于拷贝内容的优 点是避免了 Concurrent Modification Exception,但同样 地,迭代器并
不能访问到修改后的内容,即 : 迭代器遍历的是开始遍历那 ⼀ 刻拿到的集合拷贝,在遍历期 间原集
合发⽣ 的 修 改 迭代器是不知 道的。
场景: java.util.concurrent包 下的容器 都是安全失败,可以在多线程下 并 发 使 ⽤,并 发 修 改,⽐
如 CopyOnWriteArrayList类。
6.有哪⼏种实现ArrayList线程安全的⽅法?
fail-fast是⼀种可能触发的机制 ,实际 上,ArrayList的 线程安全仍然没有保证,⼀般 , 保证
ArrayList的 线程安全可以通过这些⽅案 :
使 ⽤ Vector 代替 ArrayList。(不推荐, Vector是⼀个历史遗留类)
使 ⽤ Collections.synchronizedList 包装 ArrayList,然后操 作 包装后的 list。
使 ⽤ CopyOnWriteArrayList 代替 ArrayList。
在 使 ⽤ ArrayList 时,应 ⽤ 程 序通过同步机制去控制 ArrayList 的 读写。
7.CopyOnWriteArrayList了解多少?
CopyOnWriteArrayList就是线程安全版本的 ArrayList。
它的名字叫 CopyOnWrite ——写 时复制 , 已经明⽰了它的原理。
CopyOnWriteArrayList采 ⽤了⼀种读写分 离 的 并 发 策略。 CopyOnWriteArrayList容 器允许并发 读 ,
读操作是⽆锁 的,性 能 较 ⾼。⾄于写操作,⽐如向容器 中 添加⼀个元素,则⾸先 将 当前容器 复 制 ⼀ 份 ,
然后在新副本上 执 ⾏ 写操作,结束之后 再将原容器 的 引 ⽤指向新 容 器 。