CopyOnWrite容器
什么是CopyOnWrite容器
在说到CopyOnWrite
容器之前我们先来谈谈什么是CopyOnWrite
机制,CopyOnWrite
是计算机设计领域中的一种优化策略,也是一种在并发场景下常用的设计思想——写入时复制思想。
那什么是写入时复制思想呢?就是当有多个调用者同时去请求一个资源数据的时候,有一个调用者出于某些原因需要对当前的数据源进行修改,这个时候系统将会复制一个当前数据源的副本给调用者修改。
CopyOnWrite
容器即写时复制的容器,当我们往一个容器中添加元素的时候,不直接往容器中添加,而是将当前容器进行copy,复制出来一个新的容器,然后向新容器中添加我们需要的元素,最后将原容器的引用指向新容器。
这样做的好处在于,我们可以在并发的场景下对容器进行"读操作"而不需要"加锁",从而达到读写分离的目的。从JDK 1.5 开始Java并发包里提供了两个使用CopyOnWrite
机制实现的并发容器 ,分别是CopyOnWriteArrayList
和CopyOnWriteArraySet
。这里着重给大家介绍一下CopyOnWriteArrayList
。
CopyOnWriteArrayList
优点: CopyOnWriteArrayList
经常被用于“读多写少”的并发场景,是因为CopyOnWriteArrayList
无需任何同步措施,大大增强了读的性能。在Java中遍历线程非安全的List(如:ArrayList和 LinkedList)的时候,若中途有别的线程对List容器进行修改,那么会抛出ConcurrentModificationException异常。CopyOnWriteArrayList
由于其"读写分离",遍历和修改操作分别作用在不同的List容器,所以在使用迭代器遍历的时候,则不会抛出异常。
缺点: 第一个缺点是CopyOnWriteArrayList每次执行写操作都会将原容器进行拷贝了一份,数据量大的时候,内存会存在较大的压力,可能会引起频繁Full GC(ZGC因为没有使用Full GC)。比如这些对象占用的内存比较大200M左右,那么再写入100M数据进去,内存就会多占用300M。
第二个缺点是CopyOnWriteArrayList由于实现的原因,写和读分别作用在不同新老容器上,在写操作执行过程中,读不会阻塞,但读取到的却是老容器的数据。
现在我们来看一下CopyOnWriteArrayList的add操作源码,它的逻辑很清晰,就是先把原容器进行copy,然后在新的副本上进行"写操作",最后再切换引用,在此过程中是加了锁的。
我们再来看一下remove操作的源码,remove的逻辑是将要remove元素之外的其他元素拷贝到新的副本中,然后切换引用,再将原容器的引用指向新的副本中,因为remove操作也是"写操作"所以也是要加锁的。
我们再来看看CopyOnWriteArrayList
效率最高的读操作的源码
由上可见“读操作”是没有加锁,直接读取。
总结
CopyOnWrite容器有数据一致性的问题,它只能保证最终数据一致性。
所以如果我们希望写入的数据马上能准确地读取,请不要使用CopyOnWrite容器。
最后更新于
这有帮助吗?