CopyOnWriteArrayList 的具体介绍
Posted ABin-阿斌
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CopyOnWriteArrayList 的具体介绍相关的知识,希望对你有一定的参考价值。
文章目录
- 一、CopyOnWriteArrayList 简介
- 二、CopyOnWriteArrayList 是如何做到的
- 三、CopyOnWriteArrayList 读取和写入源码简单分析
- 四、CopyOnWriteArrayList的使用场景
- 五、CopyOnWriteArrayList 与 Vector 的区别
- 六、参数文献
一、CopyOnWriteArrayList 简介
-
在很多应用场景中,读操作可能会远远大于写操作。由于读操作根本不会修改原有的数据,因此如果每次读取都进行加锁操作,其实是一种资源浪费。我们应该允许多个线程同时访问 List 的内部数据,毕竟读操作是线程安全的。
-
这和
ReentrantReadWriteLock
读写锁的思想非常类似,也就是 读读共享、写写互斥、读写互斥、写读互斥。 -
JDK中提供了
CopyOnWriteArrayList
类,相比于在读写锁的思想又更进一步。为了将读取的性能发挥到极致,CopyOnWriteArrayList
读取是完全不用加锁的,并且更厉害的是:写入也不会阻塞读取操作,只有写入和写入之间需要进行同步等待,读操作的性能得到大幅度提升。
二、CopyOnWriteArrayList 是如何做到的
-
CopyOnWriteArrayList
类的所有可变操作(add,set等等)都是通过创建底层数组的新副本来实现的。当 List 需要被修改的时候,并不直接修改原有数组对象,而是对原有数据进行一次拷贝,将修改的内容写入副本中。 -
写完之后,再将修改完的副本替换成原来的数据,这样就可以保证写操作不会影响读操作了。
-
从
CopyOnWriteArrayList
的名字可以看出,CopyOnWriteArrayList
是满足CopyOnWrite
的 ArrayList。 -
所谓
CopyOnWrite
的意思:就是对一块内存进行修改时,不直接在原有内存块中进行写操作,而是将内存拷贝一份,在新的内存中进行写操作,写完之后,再将原来指向的内存指针指到新的内存,原来的内存就可以被回收。
三、CopyOnWriteArrayList 读取和写入源码简单分析
1、CopyOnWriteArrayList 读取操作的实现
-
读取操作没有任何同步控制和锁操作,理由就是内部数组 array 不会发生修改,只会被另外一个 array 替换,因此可以保证数据安全。
-
get方法: 底层源码
2、CopyOnWriteArrayList 写入操作的实现
-
CopyOnWriteArrayList 写入操作
add()
方法在添加集合的时候加了锁,保证同步,避免多线程写的时候会 copy 出多个副本。 -
add方法: 底层源码
-
由于所有的写操作都是在新数组进行的,这个时候如果有线程并发的写,则通过锁来控制,如果有线程并发的读,则分几种情况:
- 1、如果写操作未完成,那么直接读取原数组的数据;
- 2、如果写操作完成,但是引用还未指向新数组,那么也是读取原数组数据;
- 3、如果写操作完成,并且引用已经指向了新的数组,那么直接从新数组中读取数据。
-
可见, CopyOnWriteArrayList 的读操作是可以不用加锁的。
四、CopyOnWriteArrayList的使用场景
1、CopyOnWriteArrayList 的不足之处:
-
由于写操作的时候,需要拷贝数组,会消耗内存,如果原数组的内容比较多的情况下,可能导致 young gc 或者 full gc
-
不能用于实时读的场景,像拷贝数组、新增元素都需要时间,所以调用一个 set 操作后,读取到数据可能还是旧的,虽然CopyOnWriteArrayList 能做到最终一致性,但是还是没法满足实时性要求
-
CopyOnWriteArrayList 合适读多写少的场景,不过这类慎用
-
因为谁也没法保证 CopyOnWriteArrayList 到底要放置多少数据,万一数据稍微有点多,每次 add/set 都要重新复制数组,这个代价实在太高昂了。在高性能的互联网应用中,这种操作分分钟引起故障。
五、CopyOnWriteArrayList 与 Vector 的区别
-
Vector 是【绝对】线程安全的,CopyOnWriteArrayList 只能保证读线程会读到【已完成】的写结果,但无法像 Vector一样实现读操作的【等待写操作完成后再读最新值】的能力
-
CopyOnWriteArrayList 读性能远高于 Vector,并发线程越多优势越明显
-
CopyOnWriteArrayList 占用更多的内存空间
-
Vector 不能避免 ConcurrentModificationException 问题,而 CopyOnWriteArrayList 不存在这个问题。
六、参数文献
以上是关于CopyOnWriteArrayList 的具体介绍的主要内容,如果未能解决你的问题,请参考以下文章
java 集合框架-CopyOnWriteArrayList
java 集合框架-CopyOnWriteArrayList
为什么线程安全的List推荐使用CopyOnWriteArrayList,而不是Vector