CopyOnWriteArrayList实现原理

1.CopyOnWrite容器即写时复制的容器。当我们新添加一个元素到容器时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。从JDK1.5开始Java并发包里提供了两个使用CopyOnWrite机制实现的并发容器,它们是CopyOnWriteArrayList和CopyOnWriteArraySet。下面是CopyOnWriteArrayList源码实现:

public class CopyOnWriteArrayList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
    private static final long serialVersionUID = 8673264195747942595L;

    /** 定义一个重入锁,用来保护元素非原子操作时线程安全 */
    final transient ReentrantLock lock = new ReentrantLock();

    /** 使用数组来存放数据 */
    private transient volatile Object[] array;
    
    //初始化数组容量
    public CopyOnWriteArrayList() {
        setArray(new Object[0]);
    }
    
    final void setArray(Object[] a) {
        array = a;
    }

    //添加一个元素,每次宽容为当前容量+1
    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 Object[] getArray() {
        return array;
    }
    
    @SuppressWarnings("unchecked")
    /**
        * 开始拷贝
     * @param original  原数组变量
     * @param newLength 新数组容量长度
     * @return
     */
    public static <T> T[] copyOf(T[] original, int newLength) {
        return (T[]) copyOf(original, newLength, original.getClass());
    }
    
    public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
        @SuppressWarnings("unchecked")
        T[] copy = ((Object)newType == (Object)Object[].class)
            ? (T[]) new Object[newLength]
            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }
    
    //获取指定下标的元素
    public E get(int index) {
        return get(getArray(), index);
    }
    
    @SuppressWarnings("unchecked")
    private E get(Object[] a, int index) {
        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)); // 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();
        }
    }
    
    // 指定下标设置一个元素,如果值相同不做任何操作
    public E set(int index, E element) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            E oldValue = get(elements, index); // 获取指定下标元素的值

            if (oldValue != element) {
                int len = elements.length;
             // 拷贝数组,开辟一块新的空间进行拷贝
                Object[] newElements = Arrays.copyOf(elements, len); 
                newElements[index] = element;
                setArray(newElements);
            } else {
                // Not quite a no-op; ensures volatile write semantics
                setArray(elements);
            }
            return oldValue;
        } finally {
            lock.unlock();
        }
    }
    ........
}

参考:https://www.cnblogs.com/dolphin0520/p/3938914.html

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值