Copy-On-Write
简称COW
,是一种程序设计中的优化策略,其实现思路是大家都在共享一个内容,当有人想要修改内容的时候,就创建一个改内容的副本,对副本进行修改,然后再将原本的引用指向副本,完成内容的修改。是一种读写分离的并发策略,也是一种延时惰性策略;
opyOnWrite
容器,即写时复制容器。从 JDK1.5 开始,Java 并发包提供了两个实现了Copy-On-Write
的容器,分别是CopyOnWriteArrayList
和CopyOnWriteArraySet;
CopyOnWriteArrayList/CopyOnWriteArraySet 的基本思想是只对写加锁,一旦对容器有修改,就“复制”一新集合,在新集合上修改,然后将新集合复制给旧的引用;
- 为了保证无锁的读操作能够看到写操作的变化,因此数组array是volatile类型的。
- get/indexOf/iterator等操作都是无锁的,同时也可以看到所操作的都是某一时刻array的镜像(这得益于数组是不可变化的)。
- add/set/remove/clear等元素变化的都是需要加锁的,这里使用的是ReentrantLock。
CopyOnWrite容器适用于读多写少的场景。因为写操作时,需要复制一个容器,造成内存开销很大,也需要根据实际应用把握初始容器的大小;
优点:
- 读取性能很高,因为读取的时候是无锁的,比较适合读多写少的场景
- 采用读写分离策略,允许读取的时候修改集合数据,没有 fail-fast 机制
缺点:
- 内存占用问题,因为
CopyOnWrite
的写时复制机制,当进行写操作,同时又有线程在读取数据的时候,内存里就会同时驻扎两个对象的内存,如果这些对象占用的内存比较大,比如说200M左右,那么再写入100M数据进去,内存就会占用300M,那么这个时候很有可能造成频繁的Yong GC和Full GC - 数据一致性问题,
CopyOnWrite
只保证数据的最终一致性,并不能保证数据的实时一致性。所以对数据实时一致性要求比较高的场景不适合使用CopyOnWrite
容器