实现原理
- 使用ReentrantLock加锁
- 底层复制新的数组,对新数组操作,然后将新数组的引用设置给集合
public E set(int index, E element) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
// 得到原数组的旧值
Object[] elements = getArray();
E oldValue = get(elements, index);
// 判断新值和旧值是否相等
if (oldValue != element) {
// 复制新数组,新值在新数组中完成
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len);
newElements[index] = element;
// 将array引用指向新数组
setArray(newElements);
} else {
// Not quite a no-op; enssures volatile write semantics
setArray(elements);
}
return oldValue;
} finally {
lock.unlock();
}
}
缺点
-
内存占用:如果CopyOnWriteArrayList经常要增删改里面的数据,经常要执行
add()、set()、remove()的话,那是比较耗费内存的。 -
- 因为我们知道每次
add()、set()、remove()这些增删改操作都要复制一个数组出来。
- 因为我们知道每次
-
数据一致性:CopyOnWrite容器只能保证数据的最终一致性,不能保证数据的实时一致性。
-
- 从上面的例子也可以看出来,比如线程A在迭代CopyOnWriteArrayList容器的数据。线程B在线程A迭代的间隙中将CopyOnWriteArrayList部分的数据修改了(已经调用
setArray()了)。但是线程A迭代出来的是原有的数据。
- 从上面的例子也可以看出来,比如线程A在迭代CopyOnWriteArrayList容器的数据。线程B在线程A迭代的间隙中将CopyOnWriteArrayList部分的数据修改了(已经调用