CopyOnWriteArrayList源码浅析

231 阅读1分钟

成员变量

//CopyOnWriteArrayList内部持有一个重入锁,用于保证线程安全
final transient ReentrantLock lock = new ReentrantLock();

//数组,注意用volatile修饰了,保证了可见性,所以在读这个数组时是不用加锁的
private transient volatile Object[] array;

构造方法

//为成员变量array赋值了一个空数组
public CopyOnWriteArrayList() {
    setArray(new Object[0]);
}

final void setArray(Object[] a) {
    array = a;
}

常用接口

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 {
      	//释放锁放在finally块中,以保证异常情况下也能释放锁
        lock.unlock();
    }
}

//直接返回array数组
final Object[] getArray() {
    return array;
}

这里可以看出CopyOnWriteArrayList名字的由来:在写入的时候进行数组拷贝

可以发现,CopyOnWriteArrayList中并没有采用ArrayList中的1.5倍空间预分配策略

get方法

public E get(int index) {
    return get(getArray(), index);
}

//直接通过下表从数组中取元素并返回,由于数组用volatile修饰,所以不需要加锁也能保证读操作的线程安全
private E get(Object[] a, int index) {
    return (E) a[index];
}

size方法和isEmpty方法

//直接返回数组长度,也不用加锁
public int size() {
    return getArray().length;
}

//判断size是否为0即可
public boolean isEmpty() {
    return size() == 0;
}