Java:CopyOnWriteArrayList核心源码阅读

CopyOnWrite(COW):是一种用于集合的并发访问的。基本思想是:当我们往集合中写入(修改,删除,添加)元素时,并不会直接在集合中写入,而是先将集合复制出来,然后写入操作在新复制的集合中操作,完成写入操作后,再将旧集合的引用指向新集合。这种做法的好处:即实现了写入操作时线程安全,又可以在写入同时对集合进行读取操作。

CopyOnWriteArrayList类部分源码阅读:

public class CopyOnWriteArrayList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
    
	//公共锁对象
    final transient ReentrantLock lock = new ReentrantLock();

    //内部结构:数组
    private transient volatile Object[] array;

    /**
     * Gets the array.  Non-private so as to also be accessible
     * from CopyOnWriteArraySet class.
     */
    //获取数组元素
    final Object[] getArray() {
        return array;
    }

    /**
     * Sets the array.
     */
    //设置数组元素值
    final void setArray(Object[] a) {
        array = a;
    }

    //构造方法
    public CopyOnWriteArrayList() {
        setArray(new Object[0]);
    }

    //从数组a中获取index位置的元素值
    @SuppressWarnings("unchecked")
    private E get(Object[] a, int index) {
        return (E) a[index];
    }

    //获取元素
    public E get(int index) {
        return get(getArray(), index);
    }

    //在下标index位置修改元素的值为element
    public E set(int index, E element) {
    	//给当前锁重新指向一个引用
        final ReentrantLock lock = this.lock;
        //加锁
        lock.lock();
        try {
        	//得到数组元素
            Object[] elements = getArray();
            //获取下标index位置的元素element,并将值赋给oldValue
            E oldValue = get(elements, index);
            //判断获取的oldValue的值是否和要修改的元素element的值一致
            //如果不一致,就修改
            if (oldValue != element) {
            	//获取数组的长度
                int len = elements.length;
                //将数组复制,赋给变量newElement
                Object[] newElements = Arrays.copyOf(elements, len);
                //将新数组中下标为index位置修改为元素element
                newElements[index] = element;
                //将旧数组的引用指向新数组
                setArray(newElements);
            } else {
                // Not quite a no-op; ensures volatile write semantics
                setArray(elements);
            }
            return oldValue;
        } finally {
        	//释放锁
            lock.unlock();
        }
    }

    //添加元素e
    public boolean add(E e) {
    	//给当前锁重新指向一个引用
        final ReentrantLock lock = this.lock;
        //加锁
        lock.lock();
        try {
        	//得到数组元素
            Object[] elements = getArray();
            //获取数组的长度
            int len = elements.length;
            //将数组复制,赋给变量newElement(len+1是因为要添加一个元素)
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            //将数组末尾的位置添加进元素e
            newElements[len] = e;
          //将旧数组的引用指向新数组
            setArray(newElements);
            return true;
        } finally {
        	//释放锁
            lock.unlock();
        }
    }

    //在index位置添加元素element
    public void add(int index, E element) {
        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;
            //数组长度-要添加元素的下标
            int numMoved = len - index;
            //判断是否添加在末尾
            if (numMoved == 0)
            	//复制数组元素,长度为len+1,将e放入数组末尾
                newElements = Arrays.copyOf(elements, len + 1);
            else {
            	//创建一个数组,长度为len+1
                newElements = new Object[len + 1];
                //复制旧数组中下标在index前的元素
                System.arraycopy(elements, 0, newElements, 0, index);
                //复制旧数组中下标在index后的元素
                System.arraycopy(elements, index, newElements, index + 1,
                                 numMoved);
            }
            //在index位置上添加element元素
            newElements[index] = element;
          //将旧数组的引用指向新数组
            setArray(newElements);
        } finally {
            lock.unlock();
        }
    }
    
    //删除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);
            //数组长度-删除的下标-1
            int numMoved = len - index - 1;
            //判断要删除的元素是否为最后一个元素
            if (numMoved == 0)
            	//如果是,不用复制最后一个元素
                setArray(Arrays.copyOf(elements, len - 1));
            else {
            	//创建新数组,长度为len-1
                Object[] newElements = new Object[len - 1];
              //复制旧数组中下标在index前的元素
                System.arraycopy(elements, 0, newElements, 0, index);
              //复制旧数组中下标在index后(不包括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;
            //如果移动的位置为0
            if (numMoved == 0)
            	//复制数组elements中的元素,长度为newLen,引用指向复制后的数组
                setArray(Arrays.copyOf(elements, newlen));
            else {
            	//如果移动的位置不为0
                Object[] newElements = new Object[newlen];
                //复制数组elements中从0开始的元素,到新数组中从0开始到删除起始下标的位置
                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) {
                // temp array holds those elements we know we want to keep
            	//记录新数组的下标
                int newlen = 0;
                //创建新数组
                Object[] temp = new Object[len];
                //遍历旧数组
                for (int i = 0; i < len; ++i) {
                	//获取数组中位置i的元素
                    Object element = elements[i];
                    //判断c集合中是否包含当前元素
                    if (!c.contains(element))
                    	//不包含,将当前元素放入新集合中
                        temp[newlen++] = element;
                }
                //如果新集合的长度不等于旧集合的长度
                if (newlen != len) {
                	//使用Arrays工具类中的copy()复制数组,并将引用指向复制后的数组
                    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();
        }
    }

   //将c集合中的元素添加到当前集合
    public boolean addAll(Collection<? extends E> c) {
    	//判断两个集合的类型是否一致
    	//判断集合的类型是否是CopyOnWriteArrayList
        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;
            //判断原有长度是否为0,判断是否为Object[]类型
            //长度为0,类型一样,说明原有集合列表为空
            if (len == 0 && cs.getClass() == Object[].class)
            	//将引用指向cs集合
                setArray(cs);
            else {
            	//复制旧数组中的元素,长度为旧数组的长度和cs数组的长度
                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()方法进行排序
            Arrays.sort(es, c);
            setArray(newElements);
        } finally {
            lock.unlock();
        }
    }

    //比较内容
    public boolean equals(Object o) {
    	//判断当前的值和传入的值
        if (o == this)
        	//如果相等,返回true
            return true;
        //判断传入的类型是否是List集合
        if (!(o instanceof List))
            return false;
        //将当前元素转型为集合
        List<?> list = (List<?>)(o);
        //调用iterator():迭代器
        Iterator<?> it = list.iterator();
        Object[] elements = getArray();
        int len = elements.length;
        //遍历数组
        for (int i = 0; i < len; ++i)
        	//如果集合中没有下一个元素或者调用eq()内容不相同
            if (!it.hasNext() || !eq(ele ments[i], it.next()))
                return false;
        //是否有下一个元素
        if (it.hasNext())
            return false;
        return true;
    }
    
    //计算hash值
    public int hashCode() {
        int hashCode = 1;
        Object[] elements = getArray();
        int len = elements.length;
        //遍历数组
        for (int i = 0; i < len; ++i) {
        	//根据下标获取值
            Object obj = elements[i];
            //判断obj是否等于0 ,如果为0,返回0+31*1
            //否则调用Object类的hashCode()方法计算此元素的hash值
            hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());
        }
        return hashCode;
    }
}
 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值