CopyOnWriteArrayList簡述

CopyOnWriteArrayList簡單閱讀源碼

CopyOnWriteArrayList是Java併發包中提供的一個併發容器,它是個線程安全且讀操做無鎖的ArrayList,寫操做則經過建立底層數組的新副原本實現,是一種讀寫分離的併發策略,咱們也能夠稱這種容器爲"寫時複製器",Java併發包中相似的容器還有CopyOnWriteSet。本文會對CopyOnWriteArrayList的實現原理及源碼進行分析。數組

集合框架中的ArrayList是非線程安全的,Vector雖是線程安全的,但因爲簡單粗暴的鎖同步機制,性能較差。而CopyOnWriteArrayList則提供了另外一種不一樣的併發處理策略(固然是針對特定的併發場景)。安全

  不少時候,咱們的系統應對的都是讀多寫少的併發場景。CopyOnWriteArrayList容器容許併發讀,讀操做是無鎖的,性能較高。至於寫操做,好比向容器中添加一個元素,則首先將當前容器複製一份,而後在新副本上執行寫操做,結束以後再將原容器的引用指向新容器。併發

 

優缺點分析

  瞭解了CopyOnWriteArrayList的實現原理,分析它的優缺點及使用場景就很容易了。app

  優勢:框架

  讀操做性能很高,由於無需任何同步措施,比較適用於讀多寫少的併發場景。Java的list在遍歷時,若中途有別的線程對list容器進行修改,則會拋出ConcurrentModificationException異常。而CopyOnWriteArrayList因爲其"讀寫分離"的思想,遍歷和修改操做分別做用在不一樣的list容器,因此在使用迭代器進行遍歷時候,也就不會拋出ConcurrentModificationException異常了ide

  缺點:源碼分析

  缺點也很明顯,一是內存佔用問題,畢竟每次執行寫操做都要將原容器拷貝一份,數據量大時,對內存壓力較大,可能會引發頻繁GC;二是沒法保證明時性,Vector對於讀寫操做均加鎖同步,能夠保證讀和寫的強一致性。而CopyOnWriteArrayList因爲其實現策略的緣由,寫和讀分別做用在新老不一樣容器上,在寫操做執行過程當中,讀不會阻塞但讀取到的倒是老容器的數據。性能

源碼分析:

/**
     * 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();
        }
    }

/**
     * 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();
        }
    }

CopyOnWrireArrayList vs Vector:

最重要的區別就是synchronizedthis

/**
 * Removes the first (lowest-indexed) occurrence of the argument
 * from this vector. If the object is found in this vector, each
 * component in the vector with an index greater or equal to the
 * object's index is shifted downward to have an index one smaller
 * than the value it had previously.
 *
 * <p>This method is identical in functionality to the
 * {@link #remove(Object)} method (which is part of the
 * {@link List} interface).
 *
 * @param   obj   the component to be removed
 * @return  {@code true} if the argument was a component of this
 *          vector; {@code false} otherwise.
 */
public synchronized boolean removeElement(Object obj) {
    modCount++;
    int i = indexOf(obj);
    if (i >= 0) {
        removeElementAt(i);
        return true;
    }
    return false;
}
相關文章
相關標籤/搜索