美文网首页Android多线程
CopyOnWriteArrayList原理分析

CopyOnWriteArrayList原理分析

作者: Charles1993 | 来源:发表于2021-07-11 13:14 被阅读0次

CopyOnWriteArrayList是concurrent包中的一个线程安全的ArrayList类,这个类通过在add,set等操作的时候拷贝一个新的数组,实现了线程安全。add,set等操作我们认为是write操作。这种在write的时候拷贝对象来实现线程安全的操作就叫做CopOnRight.
当需要对容器进行write操作时,先拷贝一个数组。再对数据进行write,然后再用新数组代替原数组。
接下来我们对比ArrayList和CopyOnWriteArrayList来分析:

    // ArrayList
    transient Object[] elementData;
    /**
     * Returns the element at the specified position in this list.
     *
     * @param  index index of the element to return
     * @return the element at the specified position in this list
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E get(int index) {
        Objects.checkIndex(index, size);
        return elementData(index);
    }
    E elementData(int index) {
        return (E) elementData[index];
    }
    
    // CopyOnWriteArrayList
    private transient volatile Object[] array;
    public E get(int index) {
        return elementAt(getArray(), index);
    }
    static <E> E elementAt(Object[] a, int index) {
        return (E) a[index];
    }

可以看到CopyOnWriteArrayList和ArrayList除了多一个volatile字段来确保可见性,确保数组被写后可以马上被其他线程读取,并没有太多不同。
接下来我们以add为例,看看CopyOnWriteArrayList是怎么确保安全的。

    // ArrayList
    transient Object[] elementData;
    /**
     * 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) {
        modCount++;
        add(e, elementData, size);
        return true;
    }
    /**
     * This helper method split out from add(E) to keep method
     * bytecode size under 35 (the -XX:MaxInlineSize default value),
     * which helps when add(E) is called in a C1-compiled loop.
     */
    private void add(E e, Object[] elementData, int s) {
        if (s == elementData.length)
            elementData = grow();
        elementData[s] = e;
        size = s + 1;
    }
    
    // CopyOnWriteArrayList
    
    /**
     * The lock protecting all mutators.  (We have a mild preference
     * for builtin monitors over ReentrantLock when either will do.)
     */
    final transient Object lock = new Object();
    /** The array, accessed only via getArray/setArray. */
    private transient volatile Object[] array;
    /**
     * 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) {
        synchronized (lock) {
            Object[] es = getArray();
            int len = es.length;
            es = Arrays.copyOf(es, len + 1);
            es[len] = e;
            setArray(es);
            return true;
        }
    }

可以看到,在add时候,ArrayList只有在数组长度不够时会创建新新的数组,而CopyOnWriteArrayList每次add的时候都会先上锁,然后创建一个新的数组并将数据写进去,最后用新的数组代替原有数组,释放锁资源。
其他set,remove等操作流程类似。

相关文章

网友评论

    本文标题:CopyOnWriteArrayList原理分析

    本文链接:https://www.haomeiwen.com/subject/wvekpltx.html