美文网首页
CopyOnWriteArrayList

CopyOnWriteArrayList

作者: 归来依旧少女 | 来源:发表于2019-07-07 18:31 被阅读0次

    一、介绍

    public class CopyOnWriteArrayList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    

    CopyOnWriteArrayList继承了List接口,类如其名,再写时复制,以保证线程安全。

    CopyOnWriteArrayList的成员变量:

        final transient ReentrantLock lock = new ReentrantLock(); 
    

    使用了ReentrantLock,每次写操作时获取锁。

        private transient volatile Object[] array;
    

    array是CopyOnWriteArrayList里面保存的数据,transient修饰就是序列化时数据不进行序列化,volatile修饰则保障了内存可见性。

    二、函数

    2.1 构造函数

    public CopyOnWriteArrayList() {
        setArray(new Object[0]);
    }
    final void setArray(Object[] a) {
        array = a;
    }
    

    构造函数时创建一个空的Object类型的数组,array指向这个空数组。


    构造函数.png

    2.2 add()

    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;
                //将array指向新数组
                setArray(newElements);
                return true;
            } finally {
                lock.unlock();
            }
        }
    

    写之前总是先获取锁,然后创建一个新数组(包含原数组的内容和要添加的新元素),再将array指向新的数组。所以写操作是线程安全的,但是这样每次写的时候都要创建新数组,复制原数组的数据,是很耗时的。


    添加.png

    2.3 get()

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

    get就是直接用数组下标的方式获取,没有通过锁的方式去获取,所以读是不会线程阻塞的。

    三、总结

    CopyOnWriteArrayList是线程安全的,但是每次修改操作时都伴随大量的复制,效率会比较低下。所以CopyOnWriteArrayList适用于读远远大于写的并发场景下。

    相关文章

      网友评论

          本文标题:CopyOnWriteArrayList

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