CopyOnWriteArrayList 源码解析和设计思路
在 ArrayList
的类注释上,JDK 就提醒了我们,如果要把 ArrayList 作为共享变量的话,是线程不安全的,推荐我们自己加锁或者使用 Collections.synchronizedList
方法,其实 JDK 还提供了另外一种线程安全的 List
,叫做 CopyOnWriteArrayList
,这个 List
具有以下特征:
1.线程安全的,多线程环境下可以直接使用,无需加锁;
2.通过锁 + 数组拷贝 + volatile 关键字保证了线程安全;
3.每次数组操作,都会把数组拷贝一份出来,在新数组上进行操作,操作成功之后再赋值回去。
整体架构
从整体架构上来说,CopyOnWriteArrayList
数据结构和 ArrayList
是一致的,底层是个数组,只不过 CopyOnWriteArrayList
在对数组进行操作的时候,基本会分四步走:
- 加锁;
- 从原数组中拷贝出新数组;
- 在新数组上进行操作,并把新数组赋值给数组容器;
- 解锁。
除了加锁之外,CopyOnWriteArrayList
的底层数组还被 volatile 关键字修饰,意思是一旦数组被修改,其它线程立马能够感知到,代码如下:
1 | private transient volatile Object[] array; |
整体上来说,CopyOnWriteArrayList
就是利用锁 + 数组拷贝 + volatile 关键字保证了 List 的线程安全。
类注释
我们看看从CopyOnWriteArrayList
的类注释上能得到哪些信息:
- 所有的操作都是线程安全的,因为操作都是在新拷贝数组上进行的;
- 数组的拷贝虽然有一定的成本,但往往比一般的替代方案效率高;
- 迭代过程中,不会影响到原来的数组,也不会抛出 ConcurrentModificationException 异常。
接着我们来看下 CopyOnWriteArrayList
的核心方法源码。
新增
新增有很多种情况,比如说:新增到数组尾部、新增到数组某一个索引位置、批量新增等等,操作的思路还是我们开头说的四步,我们拿新增到数组尾部的方法举例,来看看底层源码的实现:
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 ahao!
评论