Java JUCパッケージソース分析-CopyOnWriteArrayListとCopyOnWriteArraySet


CopyOnWriteArrayListはスレッドが安全なArrayListと見なすことができ,下位データ構造は配列である.主な実装プロセスはその名前のように、書く(追加、削除、変更)ときに、まずcopyでコピーを出して、それからコピーに操作して、最後にコピーを元の配列に割り当てて、全体のプロセスはReentrantLockのlockの下で完成します.
スレッドの安全を保証するために、読み取りをブロックしないことを目的としています.
データを格納するのはvolatileで修飾された配列であり,マルチスレッドシーンで修正後の最新のデータを読み取ることが保証される.次のように解釈されます.
Java言語仕様では、最適な速度を得るために、スレッドが共有メンバー変数のプライベートコピーを保存し、スレッドが同期コードブロックに入ったり離れたりしたときにのみ共有メンバー変数の元の値と比較できることを示しています.私たちは取得または反復するときにロックをかけていないので、volatile修飾を加えないと、各スレッドが表示するか、修正前の古い値が表示される可能性があります.
配列コピーの過程で大量のArraysを使った.copyof()メソッド、このメソッドは実はSystemを呼び出した.Arraycopy()メソッド
反復プロセスではremove,add,setはサポートされていません
CopyOnWriteArraySetはCopyOnWriteArrayListに完全に基づいており、そのaddメソッドはCopyOnWriteArrayListを呼び出したaddIfAbsent()メソッドである
ソースコード:
public class CopyOnWriteArrayList
    implements List, RandomAccess, Cloneable, java.io.Serializable {
    private static final long serialVersionUID = 8673264195747942595L;

    //     ,          
    final transient ReentrantLock lock = new ReentrantLock();

    //       :  
    private transient volatile Object[] array;

    //     
    final Object[] getArray() {
        return array;
    }

    //     
    final void setArray(Object[] a) {
        array = a;
    }

    //         
    public CopyOnWriteArrayList() {
        setArray(new Object[0]);
    }

    //                
    public CopyOnWriteArrayList(Collection extends E> c) {
        Object[] elements;
        //       CopyOnWriteArrayList ,     Collection        
        if (c.getClass() == CopyOnWriteArrayList.class)
            elements = ((CopyOnWriteArrayList>)c).getArray();
        else {
            // c     
            elements = c.toArray();
            // toArray   Object[]           Object[]  
            if (elements.getClass() != Object[].class)
                elements = Arrays.copyOf(elements, elements.length, Object[].class);
        }
        //     
        setArray(elements);
    }

    //       
    public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        //   
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            //               +1   
            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;
            //                           copy
            if (numMoved == 0)
                newElements = Arrays.copyOf(elements, len + 1);
            else {
                //        +1   ,       index    copy    
                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();
        }
    }
    
    //     a   index  
    private E get(Object[] a, int index) {
        return (E) a[index];
    }

    //          
    public E get(int index) {
        return get(getArray(), 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);
            //         ,          ,    copy    
            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();
        }
    }
    
    //   o    
    private static int indexOf(Object o, Object[] elements,
                               int index, int fence) {
        if (o == null) {
            for (int i = index; i < fence; i++)
                //       null   ,    == o??
                if (elements[i] == null)
                    return i;
        } else {
            for (int i = index; i < fence; i++)
                if (o.equals(elements[i]))
                    return i;
        }
        return -1;
    }
    //   o    
    public int indexOf(Object o) {
        Object[] elements = getArray();
        return indexOf(o, elements, 0, elements.length);
    }

    //                 ,CopyOnWriteArraySet        
    public boolean addIfAbsent(E e) {
        //       
        Object[] snapshot = getArray();
        // indexof     e    ,         ,  false
        //       
        //    indexof   ,   indexof                     
        return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false :
            addIfAbsent(e, snapshot);
    }

    private boolean addIfAbsent(E e, Object[] snapshot) {
        final ReentrantLock lock = this.lock;
        //   
        lock.lock();
        try {
            //        
            Object[] current = getArray();
            int len = current.length;
            //                   
            //      ,                    
            if (snapshot != current) {
                // Optimize for lost race to another addXXX operation
                //            
                int common = Math.min(snapshot.length, len); 
                //     :          ,for    [0,common],
                // indexof  [common,length],          e ,   return false 
                //              。
                for (int i = 0; i < common; i++)
                    //         [0,common]     e,        e add   ,
                    //   false。          index     ,      。
                    if (current[i] != snapshot[i] && eq(e, current[i]))
                        return false;
                //     common         e
                if (indexOf(e, current, common, len) >= 0)
                        return false;
            }
            //      +1,              true
            Object[] newElements = Arrays.copyOf(current, len + 1);
            newElements[len] = e;
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }

    //               !null         
    private static boolean eq(Object o1, Object o2) {
        //   o1=null,o2=null,   true;
        //   o1=null,o2!=null,   false;
        //   o1!=null,    equals    
        return (o1 == null) ? o2 == null : o1.equals(o2);
    }
     
    //      ,   remove,add,set
    public Iterator iterator() {
        return new COWIterator(getArray(), 0);
    }
    
    //    
    static final class COWIterator implements ListIterator {
        //        
        private final Object[] snapshot;
        //       ,            
        private int cursor;

        private COWIterator(Object[] elements, int initialCursor) {
            cursor = initialCursor;
            snapshot = elements;
        }

        public boolean hasNext() {
            return cursor < snapshot.length;
        }

        public boolean hasPrevious() {
            return cursor > 0;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            if (! hasNext())
                throw new NoSuchElementException();
            return (E) snapshot[cursor++];
        }

        @SuppressWarnings("unchecked")
        public E previous() {
            if (! hasPrevious())
                throw new NoSuchElementException();
            return (E) snapshot[--cursor];
        }

        public void remove() {
            throw new UnsupportedOperationException();
        }
        public void set(E e) {
            throw new UnsupportedOperationException();
        }
        public void add(E e) {
            throw new UnsupportedOperationException();
        }
    }

}

CopyOnWriteArraySet:
public class CopyOnWriteArraySet extends AbstractSet
        implements java.io.Serializable {
    private static final long serialVersionUID = 5457747651344034263L;

    private final CopyOnWriteArrayList al;
    //           CopyOnWriteArrayList
    public CopyOnWriteArraySet() {
        al = new CopyOnWriteArrayList();
    }
    // add      CopyOnWriteArrayList addIfAbsent
    public boolean add(E e) {
        return al.addIfAbsent(e);
    }
    //         CopyOnWriteArrayList   ......
}