【Java 集合】之 CopyOnWriteArrayList

目录

  • 一、CopyOnWrite 机制
  • 二、CopyOnWriteArrayList

一、CopyOnWrite 机制


1、CopyOnWrite 原理

CopyOnWrite 简称 COW,翻译为写时复制,它是一种读写分离思想的应用。当我们对一个容器进行修改操作添加、删除、编辑)时候,不会直接对当前容器修改,而是先将当前容器进行 Copy,复制出一个新的容器,然后在这个新的容器里进行修改元素的操作,而后面进行的读操作则继续在旧容器中读取。 修改完之后,再将原容器的引用指向新的容器,而旧的容器则进行垃圾回收。

写时复制只对修改操作进行加锁(写锁),而对于读操作则不进行加锁,这样的好处是即不会造成并发修改异常,也不会影响并发读取操作。


2、CopyOnWrite 适用的场景

从 CopyOnWrite 原理可以知道,写时复制只适合读多写少的场景,比如用户的白名单、黑名单等等。


3、CopyOnWrite 的优缺点

优点:

读写分离保证了读操作的并发不受影响,进行编辑操作操作会复制一份进行修改不会对影响旧的容器数据,因此不会抛出并发修改异常。

缺点:

  • 占用内存: 由于进行写操作时会对旧数据进行复制一份,如果原先的数据比较大的话会占用比较多的内存,可能造成频繁的 Yong GC 和 Full GC。针对内存占用问题,可以考虑使用其他的并发容器,如 ConcurrentHashMap。
  • 数据一致性问题: CopyOnWrite 容器只能保证数据的最终一致性,不能保证数据的实时一致性。所以如果你希望写入的的数据,马上能读到,请不要使用 CopyOnWrite 容器。

二、CopyOnWriteArrayList


1、ArrayList 遍历过程中删除的问题

当我们使用 forEach 遍历 ArrayList 时删除元素都会得到一个java.util.ConcurrentModificationException 的错误。这是因为在 ArrayList 的 remove() 方法中,有一个参数 modCount 专门用来记录修改的次数,每删除一次就 modCount++。在 forEach 遍历集合时,首先会记录 final int expectedModCount = modCount,若是遍历过程中发现 expectedModCount!=modCount,则会抛出错误。

所以使用 ArrayList 时,如果你有遍历删除某个元素的场景,我们可以使用迭代器来删除。

2、CopyOnWriteArrayList 的原理

CopyOnWriteArrayList 就是写时复制的一种应用,用来保证线程数据安全。在遍历 CopyOnWriteArrayList 的过程中,如果要对其进行编辑操作的话,会复制一份新的数组容器对象用于编辑操作,在此过程中的读操作在获取的是原先的旧容器上的数据。这样就避免了在遍历的时候进行修改操作时抛出并发修改异常问题

当编辑操作完成之后就会将旧容器的引用指向新的容器中,旧容器则会进行垃圾回收。

值得注意的是: CopyOnWriteArrayList 的迭代器实现里的 remove() 方法会直接抛出异常,因此在使用迭代器遍历元素时,不能删除元素。

你可能感兴趣的:(Java,java,CopyOnWrite)