JUC-6.2-并发容器-CopyOnWriteArrayList

了解了并发安全的 HashMap 之后,再来看看并发安全的 ArrayList ,就是 CopyOnWriteArrayList, 早期的版本中有 VectorSynchronizedList 但是这两个锁的粒度太大,所以并发效率并不高, Copy-On-Write 并发容器还包括 CopyOnWriteArraySet 用来替代同步 Set

适用场景

CopyOnWriteArrayList 适用于读操作尽可能快,写操作可以慢一点的地方,或者读取比写入多的地方

读写规则

CopyOnWriteArrayList 读取完全不需要加锁,写入也不会阻塞读取操作,只有写入和写入之间需要同步等待

设计思想

CopyOnWrite 通俗的来说,就是往容器中添加一个元素的时候,不是直接往当前容器添加,而是先将当前的容器复制一份作为一个新的容器,然后在新的容器中添加,添加完成之后,再将原容器的引用指向新的容器,所以 CopyOnWrite 容器进行并发的读的时候,不需要加锁,因为当前容器不会添加任何元素,但是这样做将不能保证数据的实时一致性

用一个案例来看一下,代码如下

public class ListTest {
    public static void main(String[] args) {
        CopyOnWriteArrayList list = new CopyOnWriteArrayList<>(new Integer[]{1, 2, 3, 4, 5});

        Iterator iterator1 = list.iterator();
        list.add(6);
        Iterator iterator2 = list.iterator();

        iterator1.forEachRemaining(System.out::println);
        iterator2.forEachRemaining(System.out::println);
        
    }
}

这段代码的运行结果如下

1
2
3
4
5
1
2
3
4
5
6

可以看到 iterator1 这个迭代器并没有6这元素

实现原理

看一下这个类的源码
JUC-6.2-并发容器-CopyOnWriteArrayList_第1张图片

这个类里面维护的就是一个数组 ,构造函数里面创建了一个 Object 长度为0的一个数组。

然后看看 add()get() 方法

JUC-6.2-并发容器-CopyOnWriteArrayList_第2张图片

首先上锁,保证只有一个线程修改,先复制,改完之后把新的再放到上面的数组中,数组引用是 volatile 修饰的,因此将旧的数组引用指向新的数组,根据 volatilehappens-before 规则,写入线程 对数组引用的修改 读取线程 是可见的

JUC-6.2-并发容器-CopyOnWriteArrayList_第3张图片

get() 方法就很简单了,直接返回

缺点

  1. 不能保证数据一致性
  2. 内存占用,写操作的时候,内存中会有两个对象

你可能感兴趣的:(java,rust,python)