CopyOnWriteArrayList

一、介绍

public class CopyOnWriteArrayList
    implements List, RandomAccess, Cloneable, java.io.Serializable

CopyOnWriteArrayList继承了List接口,类如其名,再写时复制,以保证线程安全。

CopyOnWriteArrayList的成员变量:

    final transient ReentrantLock lock = new ReentrantLock(); 

使用了ReentrantLock,每次写操作时获取锁。

    private transient volatile Object[] array;

array是CopyOnWriteArrayList里面保存的数据,transient修饰就是序列化时数据不进行序列化,volatile修饰则保障了内存可见性。

二、函数

2.1 构造函数

public CopyOnWriteArrayList() {
    setArray(new Object[0]);
}
final void setArray(Object[] a) {
    array = a;
}

构造函数时创建一个空的Object类型的数组,array指向这个空数组。


构造函数.png

2.2 add()

public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        //获取锁
        lock.lock();
        try {
            //得到当前数组里的全部元素
            Object[] elements = getArray();
            int len = elements.length;
            //复制一个新的数组,长度为原来的长度+1
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            //新数组的最后一个元素为添加的元素
            newElements[len] = e;
            //将array指向新数组
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }

写之前总是先获取锁,然后创建一个新数组(包含原数组的内容和要添加的新元素),再将array指向新的数组。所以写操作是线程安全的,但是这样每次写的时候都要创建新数组,复制原数组的数据,是很耗时的。


添加.png

2.3 get()

    public E get(int index) {
        return get(getArray(), index);
    }
    private E get(Object[] a, int index) {
        return (E) a[index];
    }

get就是直接用数组下标的方式获取,没有通过锁的方式去获取,所以读是不会线程阻塞的。

三、总结

CopyOnWriteArrayList是线程安全的,但是每次修改操作时都伴随大量的复制,效率会比较低下。所以CopyOnWriteArrayList适用于读远远大于写的并发场景下。

你可能感兴趣的:(CopyOnWriteArrayList)