读书人

juc 停的集合之六 (CopyOnWriteArrayL

发布时间: 2013-04-26 16:27:53 作者: rapoo

juc 下的集合之六 (CopyOnWriteArrayList )

一、基本思想

?? ? ? ArrayList的一个变体,通过对原来数组的拷贝,来保证不同操作情况下的线程安全。

?? ?? 这个容器类内部有大量的数组拷贝操作

二、源码解析

???? 2.1 基本数据结构

    /** The lock protecting all mutators */    transient final ReentrantLock lock = new ReentrantLock();    /** The array, accessed only via getArray/setArray. */    private volatile transient Object[] array;

?? 很简单,里面一个数组而已,声明成volatile保证一个线程的修改对其它线程立即可见

?

? ? 2.2 get操作

public E get(int index) {        return (E)(getArray()[index]); //数组的简单遍历操作,没有锁,没有拷贝    } final Object[] getArray() {        return array;    }public Object[] toArray()//返回的是一个数组副本        Object[] elements = getArray();return Arrays.copyOf(elements, elements.length);    }

?

?

??? 2.3 add操作

public void add(int index, E element) {final ReentrantLock lock = this.lock;lock.lock(); //可重入锁保证线程安全try {    Object[] elements = getArray(); //获取数组对象    int len = elements.length;    if (index > len || index < 0)throw new IndexOutOfBoundsException("Index: "+index+    ", Size: "+len);    Object[] newElements;    int numMoved = len - index;    if (numMoved == 0)newElements = Arrays.copyOf(elements, len + 1); //不需要移动,直接拷贝一个新的数组    else {newElements = new Object[len + 1];System.arraycopy(elements, 0, newElements, 0, index); //拷贝待移动之前的数组System.arraycopy(elements, index, newElements, index + 1, numMoved);//拷贝待移动的数组    }    newElements[index] = element;//设置值    setArray(newElements);//将新的数组作为修改后的数组} finally {    lock.unlock();//释放锁放在final中}    }

?2.4 remove 操作

 public E remove(int index) {final ReentrantLock lock = this.lock;lock.lock();try {    Object[] elements = getArray();    int len = elements.length;    Object oldValue = elements[index];    int numMoved = len - index - 1;    if (numMoved == 0)setArray(Arrays.copyOf(elements, len - 1));    else {Object[] newElements = new Object[len - 1];System.arraycopy(elements, 0, newElements, 0, index);System.arraycopy(elements, index + 1, newElements, index, numMoved);setArray(newElements);    }    return (E)oldValue;} finally {    lock.unlock();}    }

?很简单,和add操作基本一样

?

三、适用范围

?????? 官方解释,来自JDK源码中的注释。

?????? 尽管数组的大量拷贝的代价很大,但是在某些情况下可能会更加有效。比如说你需要用多个线程对数组大量的遍历,而你又不想同步你的遍历的时候。

因为你每次遍历其实是你当前数组的一个快照,所以你的程序永远不会出现"ConcurrentModifacationException"。

?????? 内存一致性问题:一个线程在处理这个数组的时候都是处理这个数组的副本,因此线程在处理过程中的这段时间,无法获得其它的线程对此数组的更改。

?

四、测试

?

//TODO :)

读书人网 >编程

热点推荐