CopyOnWriteArrayList是“读写分离”的容器,在写的时候是先将底层源数组复制到新数组中,然后在新数组中写,写完后更新源数组。而读只是在源数组上读。也就是,读和写是分离的。由于,写的时候每次都要将源数组复制到一个新组数中,所以写的效率不高。故而,CopyOnWriteArrayList适合并发读多于写的场景。
一:写时与读分离,但是也要加锁
“读写分离”的实现是通过在写时对原数组进行拷贝,然后在拷贝数组上写,而期间的读是读原数组。但是在写的时候需要加锁,不能并发写,因为如果多线程同时修改的话最终更新回原数组时就会发生竞态条件。
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();
}
}
二:写时读,直接在原数组读,读的是旧数据,期间所作的更新还没设置回原数组,所以是不可见的
public E get(int index) {
return get(getArray(), index);
}
三:优缺点分析
优点:读写分离,在读多于写的并发操作场景下,极大地提升性能。
缺点:由写操作时复制原数组引起的内存占用问题;
由延时更新回原数组导致的一致性问题:只能保证最终一致性,即写后的新数组能设置为源数组,但不能保证实时一致性,即修改不能立刻被读到。如需要实时一致性的就不能用CopyOnWriteArrayList了。