CopyOnWriterArrayList 和 fail-fast 有一点不理解的地方

2017-03-25 13:16:53 +08:00
 esolve

CopyOnWriterArrayList 避免 fail-fast 的机制是写线程拷贝一个 ArrayList,在这个拷贝的对象上进行修改 修改后再把对象赋值给原本的引用,而读线程则在原有的对象上操作

我想,如果写线程把新对象赋值给原引用后,那读线程不是一样面临着对象被修改的状况,从而有可能抛出出 ConcurrentMOdificationException 吗?

1074 次点击
所在节点    问与答
6 条回复
wwqgtxx
2017-03-25 13:26:56 +08:00
重点在于“写线程把新对象赋值给原引用后”,之前那个读线程拿到的迭代器依然是之前的旧 arraylist 呀,所以并不会触发 ConcurrentMOdificationException
SoloCompany
2017-03-25 17:45:25 +08:00
COW 或者叫 double buffer 机制的关键在于任何时候读取到的都是一个完整的 snapshot

这个 snapshot 是什么时候产生的呢?

如果你所理解的 read 仅仅是 get 操作,那么仅针对 ArrayList 数据结构而言,根本不需要 COW 也永远不会发生 ConcurrentModificationException 。

需要 snapshot 的是 iterator , COW 机制是保证你任何时候得到一个 iterator 它的状态都是永远不变的也永远不会因为并发而产生异常,而 failfast 机制则是相反,是在检测出并发修改的时候尽早抛出异常
esolve
2017-03-27 12:41:41 +08:00
@SoloCompany 譬如用 iterator 循环体里面读啊
或者 for(i) list(i).get 里读
SoloCompany
2017-03-27 12:52:50 +08:00
index base loop 一般而言就永远不可能发生 ConcurrentModificationException
index base loop 不可能支持 failfast 的, COW 也不会对并发有任何帮助
所有并发冲突会导致的任意错误都可能发生,包括且不限于
- IndexOutOfBoundException (结尾处的元素被 remove 了)
- 一个元素被完全跳过了(中间元素删除后,下标错误导致跳过了更多的元素)
- 一个元素被遍历多次(中间插入新元素,下标变化导致前面的元素又被遍历了一次)
esolve
2017-03-27 13:00:03 +08:00
@SoloCompany 譬如用 iterator 循环体里面读总会产生 ConcurrentModificationException 了吧
SoloCompany
2017-03-27 16:34:37 +08:00
@esolve 我只能回答 rtfm 了,请多读 javadoc

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/350228

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX