美文网首页
CopyOnWriteArrayList写时复制原理

CopyOnWriteArrayList写时复制原理

作者: 半个橙子 | 来源:发表于2018-10-31 23:33 被阅读0次

    CopyOnWriteArrayList读取时不加锁只是写入和删除时加锁,所以一个线程X读取的时候另一个线程Y可能执行remove操作。remove操作首先要获取独占锁,然后进行写时复制操作,就是复制一份当前的array数组,然后在复制的新数组里面删除线程X通过get访问的元素,比如:1。删除完成后让array指向这个新的数组。
    在线程x执行get操作的时候并不是直接通过全局array访问数组元素而是通过方法的形参a访问的,a指向的地址和array指向的地址在调用get方法的那一刻是一样的,都指向了堆内存的数组对象。之后改变array指向的地址并不影响get的访问,因为在调用get方法的那一刻形参a指向的内存地址就已经确定了,不会改变。

        public E get(int index) {
            return get(getArray(), index);
        }
        private E get(Object[] a, int index) {
            //形参直接指向了原数组,array引用地址的改变并不影响这里取值
            return (E) a[index];
        }
    
        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)
                    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);
                    //将array指向新数组
                    setArray(newElements);
                }
                return oldValue;
            } finally {
                lock.unlock();
            }
        }
    
    image.png

    删除完成后让array指向新的数组。这个时候{1,2,3}这个数组的引用计数不为0而是为1,线程x还在使用它。


    image.png

    所以,虽然线程y已经删除了index处的元素但是线程x的获取操作还是会返回index处的元素。

    相关文章

      网友评论

          本文标题:CopyOnWriteArrayList写时复制原理

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