目录
CopyOnWriteArrayList
类图
CopyOnWriteArrayList
原理
CopyOnWriteArrayList
底层使用了独占式的可重入锁ReentrantLock + volatile
CopyOnWriteArrayList
对所有读操作不加ReentrantLock
锁,在并发情况下大大提高了读操作的效率CopyOnWriteArrayList
对所有写操作,在加ReentrantLock
锁之后先复制一份新数组,在新数组上面写,然后将新数组赋值给原数组(调用setArray()
方法),最后解锁- 因此,同时进行写读操作不会阻塞,同时进行写写操作会阻塞,大大提升了并发情况下的性能
CopyOnWriteArrayList
源码
CopyOnWriteArrayList
属性
CopyOnWriteArrayList
底层使用数组实现,持有一个 Object[] array
的数组。读操作不需要加锁,因此使用了 volatile
来保证可见性,写操作需要加锁,内部肯定持有一个锁的引用 lock
。内部元素实际上是 Object
类型的,因此没有额外的结点类
public class CopyOnWriteArrayList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
// 写操作时使用的锁
final transient ReentrantLock lock = new ReentrantLock();
// 底层数组,注意 volatile 关键字
private transient volatile Object[] array;
// 获取数组,非私有的方法
final Object[] getArray() {
return array;
}
// 设置数组
final void setArray(Object[] a) {
array = a;
}
}
lock:ReentrantLock
,独占锁,多线程运行的情况下,只有一个线程会获得这个锁,只有释放锁后其他线程才能获得array
:存放数据的数组,关键是被volatile
修饰了,被volatile
修饰,就保证了可见性,也就是一个线程修改后,其他线程立即可见
CopyOnWriteArrayList
构造器
// 创建一个空列表
public CopyOnWriteArrayList() {
// 调用setArray方法,传入新建的集合,默认容量为0
setArray(new Object[0]);
}
public CopyOnWriteArrayList(Collection<? extends E> c) {
Object[] elements;
// 如果两个集合的类型一样
if (c.getClass() == CopyOnWriteArrayList.class)
// 那么直接强转并调用 getArray() 方法获取指定集合的内部数组
elements = ((CopyOnWriteArrayList<?>)c).getArray();
else {
// 转换为数组
elements = c.toArray();
if (c.getClass() != ArrayList.class)
// 如果实际类型不一致,那么只能拷贝元素,这里实际上是浅克隆
elements = Arrays.copyOf(elements, elements.length, Object[].class);
}
// 调用 setArray() 方法设置数组数据
setArray(elements);
}
public CopyOnWriteArrayList(E[] toCopyIn) {
// 创建包含 toCopyIn 数组全部元素的新 Object[] 类型的数组
setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class));
}
CopyOnWriteArrayList
添加元素
add(E e)
方法
将指定元素添加到原数组的尾部
public boolean add(E e) {
// 获取 ReentrantLock 锁对象
final ReentrantLock lock = this.lock;
// 加锁
lock.lock();
try {
// 获取原来的数组
Object[] elements = getArray();
// 原来数组的长度
int len = elements.length;
// 创建一个长度+1的新数组,并将原来数组的元素复制给新数组
O