举例数组,一般的操作在add的时候直接在考虑在数组的末尾添加新的值。但是CopyOnWrite的模式则不同:它先拷贝所有的数组,然后修改拷贝数组,再将拷贝数组赋值到原数组的变量。
参考jdk中CopyOnWrite的实现,这里只举出一些典型方法。
public class CopyOnWriteArrayList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
private static final long serialVersionUID = 8673264195747942595L;
/** The lock protecting all mutators */
transient final ReentrantLock lock = new ReentrantLock();
/** The array, accessed only via getArray/setArray. */
private volatile transient Object[] array; //volatile 关键字使其每次被赋值之后都会被其他线程看到,而不会使用线程拷贝的副本。加上赋值操作本身是原子性的所以不会冲突
/**
* Gets the array. Non-private so as to also be accessible
* from CopyOnWriteArraySet class.
*/
final Object[] getArray() {
return array;
}
/**
* Sets the array.
*/
final void setArray(Object[] a) {
array = a;
}
public E get(int index) {
return (E)(getArray()[index]); //不需要同步
}
public E set(int index, E element) {final ReentrantLock lock = this.lock;
lock.lock(); //锁定,如果已被锁定则等待
try {
Object[] elements = getArray();
Object oldValue = elements[index];
if (oldValue != element) { //写入的值与原值不一样int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len); //拷贝
newElements[index] = element;
setArray(newElements);//赋值} else {// Not quite a no-op; ensures volatile write semantics
setArray(elements);}}
return (E)oldValue;
} finally {
lock.unlock();//解锁
}
CopyOnWirte避免了写入过程中影响读操作。使“读大大多于写的情况”下,不需要对读操作添加锁。
没有评论:
发表评论