CopyOnWriteArrayList add get remove 源码解析

Posted zhangxuezhi

tags:

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

 

public class CopyOnWriteArrayList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable

  直译过来,就是写时复制的动态数组。

 

add(E e)方法,使用可重入锁ReentrantLock,来保证线程安全。通过方法copy一份新的数组数据,新数组长度加1,在末端把新数据放入新数组里面,最后用新数组替代原有数组。使用可重入锁时,注意把解锁操作放在finally里面,保证解锁操作一定会被执行,避免执行过程产生异常导致锁无法释放。

/**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return {@code true} (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            newElements[len] = e;
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }

 

add(int index, E e)方法,

同理,操作数组之前,先加锁。

然后检查索引是否越界。

最后,把原数组分成两次copy到新的长度加1的数组上,以索引index为分界线,copy时在index处预留一个空位置,然后在索引位置放入新的数据,这样新数组构造完成,替换原来的数组,释放锁,结束。

/**
     * Inserts the specified element at the specified position in this
     * list. Shifts the element currently at that position (if any) and
     * any subsequent elements to the right (adds one to their indices).
     *
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    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();
        }
    }

 

get(int index )方法,简单的通过索引,直接定位数组元素。注意这里索引时,并没有索引是否越界的检查,跟ArrayList不太一样。

    /**
     * {@inheritDoc}
     *
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E get(int index) {
        return get(getArray(), index);
    }

    @SuppressWarnings("unchecked")
    private E get(Object[] a, int index) {
        return (E) a[index];
    }

    /**
     * Gets the array.  Non-private so as to also be accessible
     * from CopyOnWriteArraySet class.
     */
    final Object[] getArray() {
        return array;
    }

 

remove(int index)方法,这个方法的实现跟上面提到的add(int index) 基本一样。只不过在这里,复制数组时,会把index位置的数据直接放弃。

/**
     * Removes the element at the specified position in this list.
     * Shifts any subsequent elements to the left (subtracts one from their
     * indices).  Returns the element that was removed from the list.
     *
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    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;
            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 oldValue;
        } finally {
            lock.unlock();
        }
    }

 

以上是关于CopyOnWriteArrayList add get remove 源码解析的主要内容,如果未能解决你的问题,请参考以下文章

高并发容器CopyOnWriteArrayList原理解析

CopyOnWriteArrayList源码解析

CopyOnWriteArrayList

CopyOnWriteArrayList分析

CopyOnWriteArrayList详解

CopyOnWriteArrayList