2009年12月28日星期一

[原创][精品]CopyOnWirte模式解决“读多于写情况下的并发问题”

CopyOnWrite顾名思义是指:在写的时候先拷贝再赋值。

举例数组,一般的操作在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避免了写入过程中影响读操作。使“读大大多于写的情况”下,不需要对读操作添加锁。

没有评论: