CopyOnWriteArrayList源码分析

1 CopyOnWriteArrayList的介绍

  • CopyOnWriteArrayList的本质是一个线程安全的ArrayList集合,

  • 它适用于读多写少的场景,

  • 它支持多个线程并发地读,但不支持多线程并发写,也就是说当一个线程在进行增、删、改的操作时,其他线程不能进行写操作,

  • 它的实现原理是在读操作的方法不加锁,而在写操作加锁,每个写操作都是赋值一份原内容,在复制的数组上进行增删改操作,最后将修改后的数组引用指向原数组的引用,这样在一个线程没修改完之前,读操作都读取的是原数组的内容,不会读取脏数据

  • 它的特点是,保证了数据的最终一致性,而不能保证数据的实时一致性,也就是说他最终获取的数据一定是正确的,但不鞥保证时刻获取的数据都是最新的数据

2 CopyOnWriteArrayList源码解读

public class CopyOnWriteArrayList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
	// 定义一个ReentrantLock类型的锁
    final transient ReentrantLock lock = new ReentrantLock();
    // 声明一个volatile修饰的Object类型的数组
    private transient volatile Object[] array;
    
    // array的getter和setter
    final Object[] getArray() {
        return array;
    }
    final void setArray(Object[] a) {
        array = a;
    }
    
    // CopyOnWriteArrayList的无参构造方法,初始化一个容量为0的Object数组
    public CopyOnWriteArrayList() {
        setArray(new Object[0]);
    }
    
    // CopyOnWriteArrayList的有参构造方法,参数类型是Collection及其子类/实现类
    public CopyOnWriteArrayList(Collection<? extends E> c) {
        Object[] elements;
        // 若初始化参数类型是CopyOnWriteArrayList
        if (c.getClass() == CopyOnWriteArrayList.class)
        	// 获取参数的array数组对象,并存到elements局部对象中
            elements = ((CopyOnWriteArrayList<?>)c).getArray();
        else {
        	// 若初始化参数类型不是CopyOnWriteArrayList
        	
        	// 将Collection类型的集合转换成数组
            elements = c.toArray();
            // 若elements不是Object[],将该elements数组复制到一个Object[]中,并传给elements
            if (elements.getClass() != Object[].class)
                elements = Arrays.copyOf(elements, elements.length, Object[].class);
        }
        // 调用set方法存值至array
        setArray(elements);
    }
    
    // set方法:修改方法
    public E set(int index, E element) {
    	// 降低作用域,得到reentrantLock锁
        final ReentrantLock lock = this.lock;
        // 加锁
        lock.lock();
        try {
        	// 获取旧数组
            Object[] elements = getArray();
            // 获取即将被修改的旧值
            E oldValue = get(elements, index);
            
            // 若旧值与新值不等
            if (oldValue != element) {
                int len = elements.length;
                // 复制旧数组至newElements
                Object[] newElements = Arrays.copyOf(elements, len);
                // 将index处的值覆盖为element
                newElements[index] = element;
                // 调用setter存值至array
                setArray(newElements);
            } else {
                // 若修改的值和原值相等,直接调用setter存值至array,还是旧数组
                setArray(elements);
            }
            // 返回修改前的值
            return oldValue;
        } finally {
        	// 释放锁
            lock.unlock();
        }
    }
    
    // 添加元素
    public boolean add(E e) {
    	// ReentrantLock对象锁
        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();
        }
    }
    // 在指定位置添加元素
    public void add(int index, E element) {
    	// ReentrantLock锁对象
        final ReentrantLock lock = this.lock;
        // 加锁
        lock.lock();
        try {
        	// 获取旧数组
            Object[] elements = getArray();
            int len = elements.length;
            // 如果传入一个不合法的下标索引,则抛异常
            if (index > len || index < 0)
                throw new IndexOutOfBoundsException("Index: "+index+
                                                    ", Size: "+len);
            // 声明一个新数组
            Object[] newElements;
            
            // 若修改的元素是最后一个元素,将原数组拷贝一份,并容量+1
            int numMoved = len - index;
            if (numMoved == 0)
                newElements = Arrays.copyOf(elements, len + 1);
            else {
            	// 若修改的元素不是最后一个元素,分段将不包含该位置的前段数组和后端数组复制到newElements数组
                newElements = new Object[len + 1];
                System.arraycopy(elements, 0, newElements, 0, index);
                System.arraycopy(elements, index, newElements, index + 1,
                                 numMoved);
            }
            // 将修改的值,存到空出来的位置
            newElements[index] = element;
            // 调用setArray将新数组存到array数组
            setArray(newElements);
        } finally {
        	// 释放锁
            lock.unlock();
        }
    }
    
    // 删除操作
    public E remove(int index) {
    	// 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;
            // 判断是否删除的是数组最后一个元素
            if (numMoved == 0)
            	// 如果是,复制除过最后一个元素外的所有元素,存到array中
                setArray(Arrays.copyOf(elements, len - 1));
            else {
            	// 若删除的不是最后一个元素,先创建一个比原来数组容量小1的数组
                Object[] newElements = new Object[len - 1];
                // 将原数组,除过删除元素下标位置,其他元素都复制到newElements
                System.arraycopy(elements, 0, newElements, 0, index);
                System.arraycopy(elements, index + 1, newElements, index,
                                 numMoved);
                // 存
                setArray(newElements);
            }
            // 返回删除前的元素
            return oldValue;
        } finally {
        	// 释放锁
            lock.unlock();
        }
    }
    // 删除连续范围内的值
    void removeRange(int fromIndex, int toIndex) {
    	// 上ReentrantLock锁
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            // 如果传入的下标参数不合法,则抛出异常
            if (fromIndex < 0 || toIndex > len || toIndex < fromIndex)
                throw new IndexOutOfBoundsException();
            int newlen = len - (toIndex - fromIndex);
            int numMoved = len - toIndex;
            // 判断删除范围是否为数组的后半段
            if (numMoved == 0)
            	// 如果是,将前半段元素复制至elements数组
                setArray(Arrays.copyOf(elements, newlen));
            else {
            	// 若否,创建一个新数组
            	// 复制范围前半段的值至elements
                Object[] newElements = new Object[newlen];
                System.arraycopy(elements, 0, newElements, 0, fromIndex);
                // 复制范围后半段的值至elements
                System.arraycopy(elements, toIndex, newElements,
                                 fromIndex, numMoved);
                // 将新数组传递给array
                setArray(newElements);
            }
        } finally {
        	// 释放锁
            lock.unlock();
        }
    }
    // 保留该集合所有包含c的值
    public boolean retainAll(Collection<?> c) {
    	// 如果传入参数为null,抛出空指针异常
        if (c == null) throw new NullPointerException();
        // 加锁
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
        	// 获取旧数组
            Object[] elements = getArray();
            // 获取旧数组的长度
            int len = elements.length;
            // 若原数组存在元素
            if (len != 0) {
                // 定义新数组长度为0
                int newlen = 0;
                // 定义一个容量为len的临时数组
                Object[] temp = new Object[len];
                // 遍历旧数组
                for (int i = 0; i < len; ++i) {
                    Object element = elements[i];
                    // 如果在c集合中包含该元素,将该元素存入临时数组
                    if (c.contains(element))
                        temp[newlen++] = element;
                }
                
                // 若符合条件元素数组temp的容量不为原数组的大小,则将容量小的数组复制至原先定义的容量大的temp数组中,目的去除空元素
                if (newlen != len) {
                    setArray(Arrays.copyOf(temp, newlen));
                    return true;
                }
            }
            return false;
        } finally {
        	// 释放锁
            lock.unlock();
        }
    }

   // 清空元素
    public void clear() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
        	// 将一个空数组设置给array
            setArray(new Object[0]);
        } finally {
            lock.unlock();
        }
    }

    // 将给定集合存入指定位置
    public boolean addAll(int index, Collection<? extends E> c) {
    	// 将集合转换成数组
        Object[] cs = c.toArray();
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            // 传入不合法的index,抛出下标越界异常
            if (index > len || index < 0)
                throw new IndexOutOfBoundsException("Index: "+index+
                                                    ", Size: "+len);
            // 如果传入集合大小为0,则返回false
            if (cs.length == 0)
                return false;
            int numMoved = len - index;
            Object[] newElements;
            // 若指定下标位置为数组末尾,则直接将给定数组添加值末尾,如果第二个参数的长度大于原数组的长度,则填充默认值
            if (numMoved == 0)
            	
                newElements = Arrays.copyOf(elements, len + cs.length);
            else {
            	// 若没在末尾添加数组,先创建一个长度为len + cs.length的数组
                newElements = new Object[len + cs.length];
                //分别将指定下标位置之前的数组复制至新数组,将剩余数组元素复制至新数组
                System.arraycopy(elements, 0, newElements, 0, index);
                System.arraycopy(elements, index,
                                 newElements, index + cs.length,
                                 numMoved);
            }
            // 将目标集合复制到指定位置
            System.arraycopy(cs, 0, newElements, index, cs.length);
            // 存
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }
}

  • 13
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值