CopyOnWriteArrayList核心源码阅读

2 篇文章 0 订阅
1 篇文章 0 订阅

CopyOnWriteArrayList介绍

CopyOnWrite 简称COW,一种用于集合的并发访问的优化策略。

思路:对一个集合容器中进行写入(有关更改操作时,即添加,修改,删除),并不会直接将操作进行在原有的集合中,而是将原集合中的元素复制(Copy)到另一个新的集合容器中,然后在对新的数组进行操作,继而将引用指向新的集合容器。

这样的好处是保证了修改操作时集合容器的线程安全,并且在写入操作时,读取操作也是可以进行的。所以copyonwrite容器是对读写分离思想的一种实现。

CopyOnWriteArrayList相当于线程安全的ArrayList,内部存储结构采用Object[ ]数组,线程安全使用ReentrantLock实现,允许多个线程并发读取,但只能有一个线程进行写入操作。

部分源码的个人解析:

import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.RandomAccess;
import java.util.concurrent.locks.ReentrantLock;

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]);
    }


    @SuppressWarnings("unchecked")
    private E get(Object[] a, int index) {
        return (E) a[index];
    }

    //	get,并没有用Reentrantlock保护,
    //	所以获得某个值是所有线程同时都可以访问
    public E get(int index) {
        return get(getArray(), index);
    }

    //	set,用Reentrantlock保护,
    //	所以同时有且只有一个线程可以访问
    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);//	调用setArray方法将集合引用指向新的集合
            } else {
                // Not quite a no-op; ensures volatile write semantics
                setArray(elements);//	值相同时直接将引用指向旧集合
            }
            return oldValue;//	返回更改前的值
        } finally {//	finally中逻辑的执行不受try块中逻辑影响,try块执行后,finally中逻辑必定执行
            lock.unlock();//	释放锁
        }
    }

    
    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();//	释放锁
        }
    }

    
    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;//计算插入位置
            if (numMoved == 0)//	最后插入
                newElements = Arrays.copyOf(elements, len + 1);//	将原数组赋值给新数组,位置不变,相当于add方法
            else {
                newElements = new Object[len + 1];//	新数组扩大容量
                System.arraycopy(elements, 0, newElements, 0, index);//	从零开始将旧数组中的值赋值给新数组,赋值index位
                System.arraycopy(elements, index, newElements, index + 1,//	将旧数组中从index位开始的值赋值给新数组且从index+1位开始,赋值numMoved位
                                 numMoved);
            }
            newElements[index] = element;//	element对新数组中的index位赋值
            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 {
            	//	同add(int,E)添加中的操作
                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)//	判断剩余是否为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();//	释放锁
        }
    }

    //	删除数组中C中的元素
    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;
            
            //	长度是否为0
            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) {
                    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]);//	指向一个为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 {
            	//	扩容至len+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")//	抑制unchecked类型警告
            E[] es = (E[])newElements;//	强制类型转换
            Arrays.sort(es, c);//	调用Arrays的排序方法
            setArray(newElements);
        } finally {
            lock.unlock();//	释放锁
        }
    }

    
    public boolean equals(Object o) {
    	//	判断地址
        if (o == this)
            return true;
        //	判断类型是否相同
        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;
    }

    

    //	计算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];
            hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode());//	新的hash值计算方式
        }
        return hashCode;
    }
	
	
}
 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Bitw-QwQ--猿究院

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值