0. COW是什么
COW:Copy On Write
写时复制,并发的一种优化策略。
当多个线程访问某共享资源时,如果其中一个线程需要更改资源内容,不直接在原资源上修改,而是复制出来一份,修改复制品,然后更新资源。
应用了读写分离的思想,读和写在不同的对象上进行。
1. 实现原理
以CopyOnWriteArrayList
为例,CopyOnWriteArraySet
是用前者实现的,但是在添加元素时会遍历检查当前数组中有无该元素:
读时直接访问,没有同步策略:
/**
* {@inheritDoc}
*
* @throws IndexOutOfBoundsException {@inheritDoc}
*/
public E get(int index) {
return get(getArray(), index);
}
@SuppressWarnings("unchecked")
private E get(Object[] a, int index) {
return (E) a[index];
}
写时复制原对象到一个新的对象,修改在新对象上进行,然后更新原对象:
/**
* Appends the specified element to the end of this list.
*
* @param e element to be appended to this list
* @return {@code true} (as specified by {@link Collection#add})
*/
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();
}
}
2. 应用场景
根据其原理我们可以知道:
- 更改资源会增加资源开销(与数据规模成正比)
- 数据更新非实时,但会保持最终一致性
所以其使用场景为不要求实时性的读多写少的并发场景。
3. 参考
CopyOnWriteArrayList
源码build 1.8.0_121-b13版本- 聊聊并发-Java中的Copy-On-Write容器
- 线程安全的CopyOnWriteArrayList介绍
- JAVA中的COPYONWRITE容器