CopyOnWrite,一个写时复制的技术来保证并发操作的安全,使用这种技术的前提是读大于写.
读读之间相容,
写写之间互斥,
读写操作相容.
实现方法:
在对底层数据进行写的时候,把底层数据复制一份,对新的备份进行写,写完后再让原来数据的指针指向新的数据.以下为JDK1.8-CopyOnWriteList类似代码.
private static class CopyOnWriteList<E> { private transient ReentrantLock lock = new ReentrantLock(); private transient volatile Object array[]; CopyOnWriteList() { array = new Object[0]; } Object[] getArray() { return array; } void setArray(Object[] objs) { array = objs; } int sizeof() { return getArray().length; } boolean empty() { return sizeof() == 0; } @SuppressWarnings("unchecked") E get(int index) { return (E) getArray()[index]; } boolean set(E e, int index) { final ReentrantLock lock = this.lock; try { lock.lock(); Object[] elements = getArray(); E oldValue = (E) elements[index]; if (oldValue != e) { int length = elements.length; Object[] newElements = Arrays.copyOf(elements, length); newElements[index] = e; setArray(newElements); } else { // 内存的可见性通过volatile的语义来实现,而不是数组的内容 setArray(elements); } return true; } finally { lock.unlock(); } } boolean add(E e) { final ReentrantLock lock = this.lock; try { lock.lock(); Object[] elements = getArray(); int length = elements.length; // Math.min(original.length, newLength) Object[] newElements = Arrays.copyOf(elements, length + 1); newElements[length] = e; setArray(newElements); return true; } finally { lock.unlock(); } } }
注意:
1.锁和底层数据都是transient,锁是基于内存的,所以写入流里没有意义,对于底层的数据,写入也是没有意义,这是一份快照数据.
2.在JDK-CopyOnWriteList底层数组进行增长的时候只+1,所以,会出现大量的复制.
3.在set方法内,即使新加入的元素和oldValue相等,也要setArray,保证volatile的语义.