CopyOnWriteArrayList 源码阅读与分析

CopyOnWriteArrayList 源码阅读与分析

      CopyOnWriteArrayList是并发包下的一个线程安全、可以实现高并发的ArrayList

首先来看看它的构造方法:

final void setArray(Object[] a) {

       array = a;

    }

 

   /**

    * Creates an empty list.

    */

   public CopyOnWriteArrayList() {

       setArray(new Object[0]);

}

    可以看到,它和ArrayList有一定的不同,它是创建一个大小为 0 的数组。ArrayList是一个空数组。

 

     下面来看看它的add(E) 方法,进一步了解它的实现原理

      顾名思义,它的名字叫CopyOnWriteArrayList(),也就是在进行写操作时,如add,remove时,会进行复制操作,即创建一个新的比当前数长度大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();

       }

    }

       add 方法并没有使用 synchronized 关键字来实现互斥,而是通过使用ReentrantLock 来进行加锁操作。可以看到,它的实现比较简单,首先加锁,然后创建一个比目前数组长度大1的新数组,再把旧数组中的值复制到新的数组中去。然后再调用setArray方法改变引用,完成add的操作,结束以后,再释放锁。

       之所以再每次的修改数组操作(add/remove等)之后,会新建一个数组,修改完毕之后,再将原来的引用指向新的数组。是为了保证数组被一个线程遍历时,没有其他线程对数组进行修改。所以也就不会抛出ArrayList并发情况下出现的ConcurrentModificationException错误。

 

 

     下面再来看看get(int) 方法

   先来看看代码的实现:

 public E get(int index) {

       return get(getArray(), index);

    }


@SuppressWarnings("unchecked")

   private E get(Object[] a, int index) {

       return (E) a[index];

    }

 

 

       可以看到,非常简单,直接获取当前数组对应的位置的元素,但是由于方法没有进行任何的加锁操作,所以可能会出现读到脏数据的现象,这样可以有比较高的性能,所以在修改少,读取多的场景下。它开始很好的选择。

 

 

 

  再来看看remove(E) 方法

   和 add 方法一样,此方法也通过ReetrantLock 来保证其线程安全。

     首先判断要删除的元素是不是最后一个元素:

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

 

         如果不是最后一个元素,就进行两次复制,先把原数组从0到index-1的数据复制到新的数组,再把index+1到最后一个元素复制到新的数组中,最后再改变引用。完成这些以后,就完成了删除的操作。

        可以看到CopyOnWriteArrayList没有像ArrayList一样的动态扩容机制,而是再每次对数组修改时都会新建一个新的数组,为了避免ConcurrentModificationException异常,但是这样也会对性能有一定的影响。而且它并没有对读操作进行任何的线程安全的操作,所以可能会出现读到脏数据的情况。所以当写操作比较多时,使用CopyOnWriteArrayList个人感觉不是好的选择。

 

CopyOnWriteArrayListJava 中的一个线程安全的集合类,它的实现原理是在写操作时创建一个新的数组来存储数据,从而实现了读写分离,保证了读操作的线程安全性。 具体的实现原理如下: 1. CopyOnWriteArrayList 内部使用一个数组来存储数据。 2. 在进行写操作(添加、修改、删除)时,先创建一个新的数组,将原数组的数据复制到新数组中,并在新数组上进行写操作。 3. 写操作完成后,将新数组赋值给原数组,从而实现了数据的更新。 4. 在进行读操作时,直接读取原数组的数据,保证了读操作的线程安全性。 CopyOnWriteArrayList 的实现原理保证了读操作的线程安全性,因为读操作不对原数组进行修改,而是读取原数组的数据。但是写操作创建一个新的数组,因此写操作的性能相对较低。 范例:<<引用[1]:CopyOnWriteArrayList原理。 文章目录 一、 CopyOnWriteArrayList介绍二、 CopyOnWriteArrayList原理三、 CopyOnWriteArrayList 属性介绍四、 构造器以及添加add方法五、 get(int index)六、 remove(int index)七、 遍历 。 引用:CopyOnWriteArrayList实现原理及源码分析。1 List list = Collections.synchronizedList(new ArrayList()); 。 CopyOnWriteArrayList 实现原理如下: 1. 内部使用一个数组来存储数据。 2. 在进行写操作时,先创建一个新的数组,将原数组的数据复制到新数组中,并在新数组上进行写操作。 3. 写操作完成后,将新数组赋值给原数组,从而实现了数据的更新。 4. 在进行读操作时,直接读取原数组的数据,保证了读操作的线程安全性。 5. 写操作创建一个新的数组,因此写操作的性能相对较低。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值