CopyOnWriteArrayList核心源码阅读

CopyOnWrite是一种用于集合的并发访问的优化策略

基本思想是:

允许多线程并发读取,只有在写入时(添加、修改、删除)的时候,才会从原来的数据复制一个副本出来,然后修改这个副本,最后把原数据替换成当前的副本。写入的同时,查询操作不会被阻塞,而是继续读取旧的数据。

这样做的好处是实现对CopyOnWrite集合容器容器写入时线程安全,但同时不会影响并发的读取操作。它是一种读写分离的思想。

CopyOnWriteArrayList相当于线程安全的ArrayList内部存储结构采用Object数组,采用ReentrantLock锁实现线程安全。

在Java的并发包里有两种集合容器使用了CopyOnWrite并发机制,分别是CopyOnWriteArrayListCopyOnWriteArraySet.

下面让我们先来看一看CopyOnWriteArrayList的源码

public class CopyOnWriteArrayList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
    //创建一个可重入锁
    final transient ReentrantLock lock = new ReentrantLock();

    //创建一个Object类型的数组  transient让定义的变量不被序列化
    private transient volatile Object[] array;
   
    //获取原来数组
    final Object[] getArray() {
        return array;
    }
    
    //将元素写入数组
    final void setArray(Object[] a) {
        array = a;
    }
    //无参构造方法创建一个长度为0的新数组
    public CopyOnWriteArrayList() {
        setArray(new Object[0]);
    }
    //读取数据,允许多个线程并发读取数据
    @SuppressWarnings("unchecked")
    //传入数组和指定下标,返回指定下标的元素
    private E get(Object[] a, int index) {
        return (E) a[index];
    }

    //根据指定下标调用get()方法从原数组中读取元素
    //返回数组和下标
    public E get(int index) {
        return get(getArray(), index);
    }

    //修改数组中的元素 传入修改位置和元素
    public E set(int index, E element) {
    	//创建锁
        final ReentrantLock lock = this.lock;
        //加锁
        lock.lock();
        try {
        	//获取原数组
            Object[] elements = getArray();
            //通过get()方法获取原数组在传入的下标位置的元素
            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();
        }
    }

    //添加元素到集合时,会对线程加ReentrantLock锁保证线程安全。
    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;
           //将原数组的引用指向新数组
            setArray(newElements);
            return true;
        } finally {
        	//释放锁
            lock.unlock();
        }
    }

    //在指定索引位置添加元素
    public void add(int index, E element) {
    	//创建锁
        final ReentrantLock lock = this.lock;
        //加锁
        lock.lock();
        try {
        	
            Object[] elements = getArray();
            int len = elements.length;
            //如果索引的范围小于0或者大于数组长度 抛异常
            if (index > len || index < 0)
                throw new IndexOutOfBoundsException("Index: "+index+
                                                    ", Size: "+len);
            Object[] newElements;
            //需要移动的元素数量
            int numMoved = len - index;
            //需要移动的元素数量为0  表示在末尾添加元素
            if (numMoved == 0)
            	//创建新数组将原数组中元素复制进去
                newElements = Arrays.copyOf(elements, len + 1);
            else {
                newElements = new Object[len + 1];
                //将原数组中0到索引位置的元素复制进新数组
                System.arraycopy(elements, 0, newElements, 0, index);
                //将索引+1位置之后的元素全部复制进新数组
                System.arraycopy(elements, index, newElements, index + 1,
                                 numMoved);
            }
            //在索引位置插入元素
            newElements[index] = element;
            //将原数组的引用指向新数组
            setArray(newElements);
        } finally {
        	//释放锁
            lock.unlock();
        }
    }
    //删除指定位置元素
    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);
                setArray(newElements);
            }
            //返回删除的元素
            return oldValue;
        } finally {
        	//释放锁
            lock.unlock();
        }
    }

   //删除指定范围的元素
    void removeRange(int fromIndex, int toIndex) {
        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)
                setArray(Arrays.copyOf(elements, newlen));
            else {
            	//创建新数组
                Object[] newElements = new Object[newlen];
                //将剩余元素复制进新数组
                System.arraycopy(elements, 0, newElements, 0, fromIndex);
                System.arraycopy(elements, toIndex, newElements,
                                 fromIndex, numMoved);
                setArray(newElements);
            }
        } finally {
            lock.unlock();
        }
    }

//求交集
    public boolean removeAll(Collection<?> c) {
    	//集合为空 抛异常
        if (c == null) throw new NullPointerException();
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            //获取原数组长度
            int len = elements.length;
            //如果原数组不为空遍历原数组判断集合中是否包含原数组中的元素,如果不包含,就将元素存入新数组
            if (len != 0) {
                int newlen = 0;
                Object[] temp = new Object[len];
                for (int i = 0; i < len; ++i) {
                    Object element = elements[i];
                    if (!c.contains(element))
                        temp[newlen++] = element;
                }
                //新数组和原数组长度不一样,将原数组的引用指向新数组
                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 {
            setArray(new Object[0]);
        } finally {
        	//释放锁
            lock.unlock();
        }
    }

   //向集合中以集合为单位添加元素
    public boolean addAll(Collection<? extends E> c) {
    	//判断传入的集合类型和当前类型是否相同(以数组为单位存储)
        Object[] cs = (c.getClass() == CopyOnWriteArrayList.class) ?
            ((CopyOnWriteArrayList<?>)c).getArray() : c.toArray();
            //获取到的数组为空
        if (cs.length == 0)
            return false;
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            if (len == 0 && cs.getClass() == Object[].class)
                setArray(cs);
            else {
            	//复制原数组内容到新数组
                Object[] newElements = Arrays.copyOf(elements, len + cs.length);
                System.arraycopy(cs, 0, newElements, len, cs.length);
                setArray(newElements);
            }
            return true;
        } finally {
            lock.unlock();
        }
    }

    //排序
    public void sort(Comparator<? super E> c) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
        	//获取原数组,并将原数组复制进新数组
            Object[] elements = getArray();
            Object[] newElements = Arrays.copyOf(elements, elements.length);
            @SuppressWarnings("unchecked") E[] es = (E[])newElements;
            //数组排序
            Arrays.sort(es, c);
            setArray(newElements);
        } finally {
            lock.unlock();
        }
    }

    //判断两个数组是否相等
    public boolean equals(Object o) {
    	//如果传入的与要比较的内存地址相同,那么他们相同
        if (o == this)
            return true;
        //判断是否为List接口类型
        if (!(o instanceof List))
            return false;
        //下转型
        List<?> list = (List<?>)(o);
        //迭代器遍历数组
        Iterator<?> it = list.iterator();
        Object[] elements = getArray();
        int len = elements.length;
        for (int i = 0; i < len; ++i)
        	//如果长度不一样,则数组不同
            if (!it.hasNext() || !eq(elements[i], it.next()))
                return false;
        if (it.hasNext())
            return false;
        return true;
    }

    //计算哈希值
    public int hashCode() {
        int hashCode = 1;
        //获取原数组
        Object[] elements = getArray();
        //获取原数组长度
        int len = elements.length;
        //遍历数组
        for (int i = 0; i < len; ++i) {
            Object obj = elements[i];
            //计算哈希值
            hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
        }
        return hashCode;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值