CopyOnWrite 容器
CopyOnWrite 容器即写时复制的容器,当我们往一个容器中添加元素的时候,不直接往容器中添加,而是将当前容器进行 copy,复制出来一个新的容器,然后向新容器中添加我们需要的元素,最后将原容器的引用指向新容器。
这样做的好处在于,我们可以在并发的场景下对容器进行”读操作”而不需要”加锁”,从而达到读写分离的目的。
CopyOnWrite 机制:当有多个调用者同时去请求一个资源数据的时候,有一个调用者出于某些原因需要对当前的数据源进行修改,这个时候系统将会复制一个当前数据源的副本给调用者修改。
CopyOnWriteArrayList
简介
CopyOnWriteArrayList 经常被用于“读多写少”的并发场景,是因为 CopyOnWriteArrayList 无需任何同步措施,大大增强了读的性能。
在 Java 中遍历线程非安全的 List(如:ArrayList 和 LinkedList)的时候,若中途有别的线程对 List 容器进行修改,那么会抛出 ConcurrentModificationException 异常。CopyOnWriteArrayList 由于其”读写分离”,遍历和修改操作分别作用在不同的 List 容器,所以在使用迭代器遍历的时候,则不会抛出异常。
内存消耗大:CopyOnWriteArrayList 每次执行写操作都会将原容器进行拷贝了一份,数据量大的时候,内存会存在较大的压力,可能会引起频繁 Full GC。
数据不一致:CopyOnWriteArrayList 由于实现的原因,写和读分别作用在不同新老容器上,在写操作执行过程中,读不会阻塞,但读取到的却是老容器的数据。
add() 方法
- 使用 synchronized 锁,保证线程安全
- 复制原容器
- 在新副本上进行写操作
- 最后切换引用
1 | /** |
remove() 方法
- 使用 synchronized 锁,保证线程安全
- 将要 remove 元素之外的其他元素拷贝到新的副本中
- 将原容器的引用指向新的副本中
1 | /** |
get() 方法
在 CopyOnWriteArrayList 中读操作效率很高,因为没有加锁
1 | _ /** |
业务场景
CopyOnWriteArrayList
主要适用于读多写少的业务场景,即读操作非常频繁而写操作相对较少的情况。因为它的读取操作不需要加锁,可以保证高效的并发读性能。
- 配置管理:在某些系统中,应用的配置数据可能存储在一个列表中,这些配置数据大部分时间是不变的,可能偶尔会被管理员更新。
CopyOnWriteArrayList
可以在读取这些配置信息时提供高效的性能。 - 版本控制:在一些场景下,可能需要快速拍摄某个数据状态的快照来记录历史数据,而不影响当前的数据处理。
- 定期统计分析:例如,在大数据分析中,可能需要对数据进行定期统计,统计完成后再进行数据刷新。数据统计阶段有大量读操作,而数据刷新阶段则是批量的写操作。