JDKソース--CopyOnWriteArrayList

7008 ワード

一、概念
クラス定義:
public class CopyOnWriteArrayList
    implements List, RandomAccess, Cloneable, java.io.Serializable 
  • はListインタフェースを実現し、List共通の動作のセットを有する.
  • はRandomAccessインタフェースを実現し、ランダムアクセスが可能である.
  • はCloneableインタフェースを実現し、浅い階層コピーを行うことができる.
  • はSerializableインタフェースを実現し、シーケンス化することができる.

  • 特徴:
  • 読み取り操作はまったくロックされていません.
  • 書き込み動作は読み出し動作をブロックしない.
  • 書き込み動作のみが書き込み動作と同期する必要がある.

  • 原理:CopyOnWriteArrayListクラスの書き込みは,下位配列の新しいコピーを作成することによって実現される.リストを修正する必要がある場合は,既存配列オブジェクトを直接修正するのではなく,既存データを一度コピーし,修正した内容をコピーに書き込む.書き終わったら、修正したコピーを元のデータに置き換えることで、書き込み操作が読み取り操作に影響しないことを保証できます.
    マルチスレッド環境では、add、setなどのスレッドAが書き込み操作を実行する前にスレッドBがget、iteratorなどの読み取り操作を実行していた場合、スレッドAが書き込み操作を実行して下位配列を完了し更新した後も、スレッドBが読み取り操作を実行するために使用する下位配列は古いものであり、弱い一致である.
    二、使用
    //TestCopyOnWriteArrayList
    public class TestCopyOnWriteArrayList {
        private static final String TAG = "CopyOnWriteArrayList";
        private CopyOnWriteArrayList list = new CopyOnWriteArrayList();
    
        public void testAdd() {
            list.add(null);
            list.add("AAA");
            list.add("BBB");
            list.addIfAbsent("CCC");
            list.addIfAbsent("CCC");
            Log.d(TAG, "zwm, add list: " + list);
        }
    
        public void testSet() {
            list.set(1, "AAAAA");
            Log.d(TAG, "zwm, set list: " + list);
        }
    
        public void testGet() {
            Log.d(TAG, "zwm, get index 1: " + list.get(1));
        }
    
        public void testRemove() {
            list.remove(null);
            Log.d(TAG, "zwm, remove list: " + list);
        }
    
        public void testSize() {
            Log.d(TAG, "zwm, size: " + list.size());
        }
    
        public void testListIterator() {
            ListIterator listIterator = list.listIterator();
            while (listIterator.hasNext()) {
                Log.d(TAG, "zwm, listIterator item: " + listIterator.next());
            }
        }
    }
    
    //    
    private void testMethod() {
        Log.d(TAG, "zwm, testMethod");
        TestCopyOnWriteArrayList testCopyOnWriteArrayList = new TestCopyOnWriteArrayList();
        testCopyOnWriteArrayList.testAdd();
        testCopyOnWriteArrayList.testSet();
        testCopyOnWriteArrayList.testGet();
        testCopyOnWriteArrayList.testRemove();
        testCopyOnWriteArrayList.testSize();
        testCopyOnWriteArrayList.testListIterator();
    }
    
    //  log
    2019-08-17 11:05:55.960 zwm, testMethod
    2019-08-17 11:05:55.962 zwm, add list: [null, AAA, BBB, CCC]
    2019-08-17 11:05:55.962 zwm, set list: [null, AAAAA, BBB, CCC]
    2019-08-17 11:05:55.962 zwm, get index 1: AAAAA
    2019-08-17 11:05:55.962 zwm, remove list: [AAAAA, BBB, CCC]
    2019-08-17 11:05:55.962 zwm, size: 3
    2019-08-17 11:05:55.963 zwm, listIterator item: AAAAA
    2019-08-17 11:05:55.963 zwm, listIterator item: BBB
    2019-08-17 11:05:55.963 zwm, listIterator item: CCC
    

    三、原理
    重要なパラメータ
    //   
    final transient ReentrantLock lock = new ReentrantLock();
    
    //       
    private transient volatile Object[] array;
    

    コンストラクタ
    //         0 CopyOnWriteArrayList
    public CopyOnWriteArrayList() {
        setArray(new Object[0]);
    }
    
    //         Collection    CopyOnWriteArrayList
    public CopyOnWriteArrayList(Collection extends E> c) {
        Object[] elements;
        if (c.getClass() == CopyOnWriteArrayList.class)
            elements = ((CopyOnWriteArrayList>)c).getArray();
        else {
            elements = c.toArray();
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elements.getClass() != Object[].class)
                elements = Arrays.copyOf(elements, elements.length, Object[].class);
        }
        setArray(elements);
    }
    
    //         toCopyIn      CopyOnWriteArrayList
    public CopyOnWriteArrayList(E[] toCopyIn) {
        setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class));
    }
    

    public boolean add(E e)
    //      
    public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        lock.lock(); //  ReentrantLock  
        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(); // finally     
        }
    }
    

    public E set(int index, E element)
    //         
    public E set(int index, E element) {
        final ReentrantLock lock = this.lock;
        lock.lock(); //  ReentrantLock  
        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(); // finally     
        }
    }
    

    public E get(int index)
    //         ,     
    public E get(int index) {
        return get(getArray(), index);
    }
    
    private E get(Object[] a, int index) {
        return (E) a[index];
    }
    

    public boolean remove(Object o)
    //     o     
    public boolean remove(Object o) {
        Object[] snapshot = getArray();
        int index = indexOf(o, snapshot, 0, snapshot.length);
        return (index < 0) ? false : remove(o, snapshot, index);
    }
    
    private boolean remove(Object o, Object[] snapshot, int index) {
        final ReentrantLock lock = this.lock;
        lock.lock(); //  ReentrantLock  
        try {
            Object[] current = getArray(); //      
            int len = current.length;
            if (snapshot != current) findIndex: {
                int prefix = Math.min(index, len);
                for (int i = 0; i < prefix; i++) {
                    if (current[i] != snapshot[i] && eq(o, current[i])) {
                        index = i;
                        break findIndex;
                    }
                }
                if (index >= len)
                    return false;
                if (current[index] == o)
                    break findIndex;
                index = indexOf(o, current, index, len);
                if (index < 0)
                    return false;
            }
            Object[] newElements = new Object[len - 1]; //     
            System.arraycopy(current, 0, newElements, 0, index); //      
            System.arraycopy(current, index + 1,
                             newElements, index,
                             len - index - 1);
            setArray(newElements); //      ,          
            return true;
        } finally {
            lock.unlock(); // finally     
        }
    }
    

    public int size()
    //      
    public int size() {
        return getArray().length;
    }
    

    四、テーマ
    ArrayList