CopyOnWriteArrayList 源码---JDK1.8

Posted emoji-emoji

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CopyOnWriteArrayList 源码---JDK1.8相关的知识,希望对你有一定的参考价值。

CopyOnWriteArrayList:通过copy一份以前元素的快照,是一种读写分离的并发策略,我们也可以称这种容器为"写时复制器"。该集合适合读多写少的场景(读没有加锁,其他更新操作均有加锁)。

 

    /** The lock protecting all mutators */
    final transient ReentrantLock lock = new ReentrantLock();

    /** The array, accessed only via getArray/setArray. */
    //volatile修饰,如果数组发生改变其他线程可见
    private transient volatile Object[] array;

 

 

元素添加,上锁,线程安全的,每次只允许一个线程对该集合修改。

 //添加元素到列表尾部
    public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        //上锁
        lock.lock();
        try {
            //获取数组的快照
            Object[] elements = getArray();
            //原数组长度
            int len = elements.length;
            //每次增加元素的时候,都会进行数组copy
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            //将新元素保存到数组中
            newElements[len] = e;
            //更新原数组
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }

 

在指定位置上添加元素:

 

 //在指定位置上添加元素,支持重复元素
    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;
            //如果为0,说明要添加的位置是尾部
            if (numMoved == 0)
                //直接len+1,copy
                newElements = Arrays.copyOf(elements, len + 1);
            else {
                //创建一个新数组,长度len+1
                newElements = new Object[len + 1];
                //copy,0--->index
                System.arraycopy(elements, 0, newElements, 0, index);
                //copy,index+1--->end
                System.arraycopy(elements, index, newElements, index + 1,
                        numMoved);
            }
            newElements[index] = element;
            setArray(newElements);
        } finally {
            lock.unlock();
        }
    }

 

更新指定位置上的元素:

 

//添加元素到指定位置,如果指定位置存在相同元素,什么也不做
    public E set(int index, E element) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            E oldValue = get(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 oldValue;
        } finally {
            lock.unlock();
        }
    }

 

获取指定位置上的元素:

 

//获取指定位置上的元素
    public E get(int index) {
        return get(getArray(), index);
    }


 //获取指定位置元素
    private E get(Object[] a, int index) {
        return (E) a[index];
    }

 

删除指定位置上的元素:

//删除指定位置上的元素
    public E remove(int index) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            //获取原数组快照
            Object[] elements = getArray();
            //获取旧数组长度
            int len = elements.length;
            //获取该位置上的旧元素
            E oldValue = get(elements, index);
            //计算出旧数组需要移动的元素数量
            int numMoved = len - index - 1;
            //为0,说明移除的是尾部元素
            if (numMoved == 0)
                setArray(Arrays.copyOf(elements, len - 1));
            //不为0,需要将将index前后2部分数组分别copy
            else {
                Object[] newElements = new Object[len - 1];
                //copy 0--index
                System.arraycopy(elements, 0, newElements, 0, index);
                //copy index+1--->end
                System.arraycopy(elements, index + 1, newElements, index,
                        numMoved);
                //更新数组
                setArray(newElements);
            }
            return oldValue;
        } finally {
            lock.unlock();
        }
    }

 

以上是关于CopyOnWriteArrayList 源码---JDK1.8的主要内容,如果未能解决你的问题,请参考以下文章

Java并发编程之CopyOnWriteArrayList源码分析

CopyOnWriteArrayList源码详解

「源码分析」CopyOnWriteArrayList 中的隐藏知识,你Get了吗?

死磕 java集合之CopyOnWriteArrayList源码分析

死磕 java集合之CopyOnWriteArrayList源码分析

CopyOnWriteArrayList并发容器源码解析