美文网首页
CopyOnWriteArrayList

CopyOnWriteArrayList

作者: sizuoyi00 | 来源:发表于2019-09-26 00:28 被阅读0次

几句话证明你看过CopyOnWriteArrayList的源码

1.特性

CopyOnWriteArrayList 是一个并发安全的 ArrayList
(1)同ArrayList所有元素都存储在动态数组中
(2)读取元素直接获取数组对应角标上的元素(不加锁)
(3)增删改时使用ReentrantLock锁 , 拷贝一份数组快照, 只改变“拷贝数组”中的元素, 最后再赋值到 CopyOnWriteArrayList 中
(4)由于写时更改的是数组快照,所以可能读到的并不是最新的数据

2.成员修饰符

    //重入锁保写操作互斥
    final transient ReentrantLock lock = new ReentrantLock();
    //volatile保证读可见性
    private transient volatile Object[] array;

3.add方法

/**
     * 添加元素到数组尾部
     */
    public boolean add(E e) {
        //1.获取全局ReentrantLock
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            //2.动态数组拷贝
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            //3.将元素e添加到“拷贝数组”
            newElements[len] = e;
            //4.拷贝数组赋值给动态数组
            setArray(newElements);
            return true;
        } finally {
            //释放锁防异常
            lock.unlock();
        }
    }
    
    public void add(int index, E element) {
        //1.获取全局ReentrantLock
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            //2.角标校验
            int len = elements.length;
            if (index > len || index < 0)
                throw new IndexOutOfBoundsException("Index: "+index+", Size: "+len);
            Object[] newElements;
            int numMoved = len - index;
            //3.动态数组拷贝
            if (numMoved == 0)
                newElements = Arrays.copyOf(elements, len + 1);
            else {
                newElements = new Object[len + 1];
                System.arraycopy(elements, 0, newElements, 0, index);
                System.arraycopy(elements, index, newElements, index + 1,
                        numMoved);
            }
            //4.将元素e添加到“拷贝数组”
            newElements[index] = element;
            //5.拷贝数组赋值给动态数组
            setArray(newElements);
        } finally {
            lock.unlock();
        }
    }

4.remove方法

/**
     * 删除指定角标元素
     */
    public E remove(int index) {
        //1.获取全局ReentrantLock
        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;
            //2.动态数组拷贝+赋值给动态数组
            if (numMoved == 0)
                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();
        }
    }

5.fail-safe机制

(1)需要复制集合,产生大量的无效对象,开销大
(2)无法保证读取的数据是目前原始数据结构中的数据。

 public ListIterator<E> listIterator(int index) {
        Object[] elements = getArray();
        int len = elements.length;
        if (index < 0 || index > len)
            throw new IndexOutOfBoundsException("Index: "+index);
        //迭代器 每次创建会将动态数组 传入到数组快照中
        return new COWIterator<E>(elements, index);
    }

    static final class COWIterator<E> implements ListIterator<E> {
        /** 动态数组快照,迭代器操作基于该快照 */
        private final Object[] snapshot;
        /** Index of element to be returned by subsequent call to next.  */
        private int cursor;

        private COWIterator(Object[] elements, int initialCursor) {
            cursor = initialCursor;
            //当原始集合的数据改变,拷贝数据中的值也不会变化。
            snapshot = elements;
        }

        public boolean hasNext() {
            return cursor < snapshot.length;
        }

        public boolean hasPrevious() {
            return cursor > 0;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            if (! hasNext())
                throw new NoSuchElementException();
             //通过快照数据获取数据,无法保证读取的数据是最新的数据
            return (E) snapshot[cursor++];
        }

        @SuppressWarnings("unchecked")
        public E previous() {
            if (! hasPrevious())
                throw new NoSuchElementException();
            return (E) snapshot[--cursor];
        }

        public int nextIndex() {
            return cursor;
        }
        public int previousIndex() {
            return cursor-1;
        }
        public void remove() {
            throw new UnsupportedOperationException();
        }
        public void set(E e) {
            throw new UnsupportedOperationException();
        }
        public void add(E e) {
            throw new UnsupportedOperationException();
        }
    }

相关文章

网友评论

      本文标题:CopyOnWriteArrayList

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