简介
长时间不关注底层信息,导致面试的时候竟然忘了这个list的实现原理,这里做下记录,以夯实基础。
CopyOnWriteArrayList是线程安全的,只在写的时候会加锁,适用多读少写的场景。主要有两个属性,一个是ReentrantLock,一个是Object[]。
CopyOnWriteArrayList内部是以数组存储数据,Object[]就是对应数组的引用。
ReentrantLock为写锁,保证同一时刻只有一个线程在修改CopyOnWriteArrayList。
代码分析
Object[]定义
private transient volatile Object[] array;
volatile
add数据之后,array引用会被替换为新数组。使用volatile修饰,保证读取的数组信息为最新。
transient
序列化对象的时候这个属性不序列化。
ReentrantLock定义
写锁。
final transient ReentrantLock lock = new ReentrantLock();
add操作
原理
add数据的时候,会先加锁,然后拷贝旧数组内容到新数组,这里新数组比旧数组长度大1。之后在新数组最后一位放入add的数据,并替换array引用,解锁。
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
从源码可以看出,CopyOnWriteArrayList每次add的时候都会新建一个数组,并发生一次拷贝动作。所以如果可以,尽量创建的时候就传入所有元素或者使用addAll批量加入。
注意
subList读的只是CopyOnWriteArrayList的一段引用,如果CopyOnWriteArrayList此引用区间内数据变化,迭代子list的时候也会读到新数据。
网友评论