美文网首页
JDK并发工具类源码--CopyOnWriteArrayList

JDK并发工具类源码--CopyOnWriteArrayList

作者: shoulda | 来源:发表于2018-06-27 19:03 被阅读0次

    1.简介

    CopyOnWriteArrayList是一个并发容器,它是一个线程安全且读操作无锁的ArrayList,写操作则通过创建底层的副本来实现,可以理解为一种读写分离的并发策略。
    在多数情况下,我们的系统一般都是面对读多写少的并发情景。CopyOnWriteArrayList容器允许并发读,读操作是无锁的,性能较高。对于写操作,当向容器添加一个元素时,首先需要将当前容器复制一份,然后在副本上进行添加操作,之后在将原引用指向新容器。

    2.方法

    2.1 add

    public boolean add(E e) {
            //ReentrantLock加锁,保证线程安全
            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();
            }
        }
    

    添加的逻辑是先将原容器copy一份,然后在新副本上执行写操作,之后再切换引用,这个过程是要加锁的。

    2.2 remove

     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)
                    //如果要删除的是列表末端数据,拷贝前len-1个数据到新副本上,再切换引用
                    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();
            }
        }
    

    删除操作将要删除元素之外的其他元素拷贝到新副本中,然后在切换引用,将原容器应用指向新副本。

    2.3 get

    public E get(int index) {
            return get(getArray(), index);
        }
    

    CopyOnWriteArrayList的读操作是不用加锁的,性能很高。

    3.总结

    1.读操作的性能非常高,比较适用于读多写少的并发场景。
    2.内存占用问题,每次进行写操作时,都要讲原容器拷贝一份,如果数据量大时,对内存的压力非常大。
    3.无法保证实时性,不能满足强一致性,CopyOnWriteArrayList由于策略的原因,写和读分别作用在新老不同的容器上。

    相关文章

      网友评论

          本文标题:JDK并发工具类源码--CopyOnWriteArrayList

          本文链接:https://www.haomeiwen.com/subject/orabyftx.html