Characteristics of CopyOnWriteArrayList

characteristic

1. Copy dependent on the underlying array, for modifying operation is thread safe

//添加元素
public boolean add(E e) {
        //低效操作(1) 加锁,使用ReentrantLoc是一个消耗性能的方式
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            //低效操作(2) 新建数组并复制元素到新数组中
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            newElements[len] = e;
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }
//移除元素
public E remove(int index) {
        //低效操作(1) 加锁
        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 {
                //低效操作(2) 拷贝
                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();
        }
    }

2. The operating cost of the set is too large, low performance, but there is a collection of elements for traversing change operation is valid

@Test
    public void testCopyOnWriteArrayListIterator() {
        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
        list.add("aa");
        list.add("bb");
        list.add("cc");
        Iterator it = list.iterator();
        while (it.hasNext()) {
            //每次遍历添加一个ff,但是不会出现在本次遍历结果中
            list.add("ff");
            System.out.println(it.next());
        }

        System.out.println("#############");
        
        //再次遍历原集合
        it = list.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }
    }

Through the results:

aa
bb
cc
#############
aa
bb
cc
ff
ff
ff

Result analysis

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

final void setArray(Object[] a) {
        //将容器中的数组重新指向了一个数组对象实例
        array = a;
    }

//遍历实现
public Iterator<E> iterator() {
        //每次获取迭代器都是根据当前array实现的,也就是说后面array的改变不影响之前迭代器获取的内容
        return new COWIterator<E>(getArray(), 0);
    }

3. do not throw ConcurrentModificationException

@Test
    public void testArrayList() {
        ArrayList<String> list = new ArrayList<>();
        list.add("aa");
        list.add("bb");
        list.add("cc");
        Iterator it = list.iterator();
        while (it.hasNext()) {
            list.add("ff");
            System.out.println(it.next());
        }
        //抛出异常
        //result java.util.ConcurrentModificationException
    }

    @Test
    public void testCopyOnWriteArrayList() {
        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
        list.add("aa");
        list.add("bb");
        list.add("cc");
        Iterator it = list.iterator();
        while (it.hasNext()) {
            list.add("ff");
            System.out.println(it.next());
        }

        //正常运行
        //result aa bb cc
    }

 

Guess you like

Origin blog.csdn.net/ly853602/article/details/88921223