CopyOnWriteArrayList vs ArrayList

package com.ljn.base;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * 总述:
 * 1.ArrayListi不是线程安全的,CopyOnWriteArrayList是线程安全的。
 * 2.ArrayListi读的时候不能写:在遍历时不能执行list.remove,list.add;但可以执行iterator.remove。
 * CopyOnWriteArrayList则相反:可执行list.remove,list.add,但不能执行iterator.remove。
 * 3.CopyOnWriteArrayList用在“读比写频繁得多”的情形下。例如多个线程要遍历,而只有少数线程要写。
 * 这样就会有一个问题:读的时候可以写吗?可以,因为:
 * 4.CopyOnWriteArrayList在执行写操作时,会把当前数组元素复制一份,例如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();
            }
    }
       
    5.CopyOnWriteArrayList当前线程开始遍历(创建Iterator)时,只会看到当前数组的元素,在遍历过程中,
    如果原数组发生了变化(其他线程执行add或remove),当前线程是看不到的。以下是创建Iterator的源码:
    
        private final Object[] snapshot;
        private int cursor;

        private COWIterator(Object[] elements, int initialCursor) {
            cursor = initialCursor;
            snapshot = elements;
        }
        
 */
public class CopyOnWriteArrayListTest {

    public final static void main(String args[]) {
        
        testCopyOnWriteArrayList();
        
        testArrayList();
        
    }

    private static void testCopyOnWriteArrayList() {
        List<String> list = new CopyOnWriteArrayList<String>();
        list.add("a");
        list.add("b");
        Iterator<String> iterator = list.iterator();
        int j = 0;
        
        //will output current array: "a" and "b"
        while (iterator.hasNext()) {
            String item = iterator.next();
            System.out.println(item);
            list.add("c" + (j++));  //操作成功。但不会马上反映在本次while循环中,因为:
            /*
            An array you are looking at currently (lets say your iterator) will never change. 
            When you read from an array you are reading it as it was when you started reading. 
            If the CopyOnWriteArrayList changes by another thread, the array you're currently observing will not be affected
            */
            
            if (item.equals("b")) {
                list.remove(item);  //ok
            }
            //iterator.remove(); //UnsupportedOperationException
        }
        System.out.println(list);   //[a, c0, c1]
    }

    private static void testArrayList() {
        List<String> list = new ArrayList<String>();
        list.add("a");
        list.add("b");
        list.add("z");
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()) {
            String item = iterator.next();
            System.out.println(item);
            iterator.remove(); //ok
            
            //list.remove(item);  //ConcurrentModificationException
            //list.add("c");  //ConcurrentModificationException
            //iterator.add();    //does not have this method on Iterator
        }
        System.out.println(list);   //empty list: []
    }
}

你可能感兴趣的:(java)