美文网首页
Java 之CopyOnWriteArrayList 分析

Java 之CopyOnWriteArrayList 分析

作者: bamboolmc | 来源:发表于2018-05-05 08:13 被阅读0次

工作原理

CopyOnWriteArrayList使用了写时复制方法,当执行add(E e)添加新元素时,会先将原有数组进行copy,然后在copy的新数组中进行写操作,写完之后,将原来数组引用指向新数组。

添加新元素时,copy新数组,引用仍然指向原数组,如下图



新元素添加成功后,改变引用指向,指向新数组,如下图


源代码

如下为执行add时的源代码

@Override 
public boolean add(E object) {
      synchronized (CopyOnWriteArrayList.this) {
          add(slice.to - slice.from, object);
          return true;
      }
  }

public synchronized boolean add(E e) {
        Object[] newElements = new Object[elements.length + 1];
        //进行数组copy
        System.arraycopy(elements, 0, newElements, 0, elements.length);
        newElements[elements.length] = e;
        elements = newElements;
        return true;
}

由如上代码可看出:
进行写操作时,是加锁synchronized的,并发的进行写操作是线程安全的。
进行读操作时,可根据写操作时操作未完成、操作已完成但引用指向未修改、写操作完成这三种情况进行考虑。根据读取当前引用指向的原则来确定是读取的copy前还是copy后数组。
CopyOnWriteArrayList的读操作是可以不用加锁的。

缺点

数据一致性问题:根据其过程分析,只有当add完毕并且引用指向新数组后,读取的数据才是最新数组数据。因此能保证最终数据一致,但无法保证add过程中的数据一致。
内存占用问题:add过程中,是做了一份copy,写操作时有两个对象驻存在内存中(注意:在复制的时候只是复制容器里的引用,只是在写的时候会创建新对象添加到新容器里,而旧容器的对象还在使用,所以有两份对象内存),占用内存翻倍,如果本身占用内存较大,并且add的内存也较大,就会导致频繁的Young Gc和Full Gc。

适用场景

适合读多写少的场景,不能用于实时读的场景。如黑名单、白名单、商品种类的访问和更新等情况。

注:
图片源自https://blog.csdn.net/linsongbin1/article/details/54581787

相关文章

网友评论

      本文标题:Java 之CopyOnWriteArrayList 分析

      本文链接:https://www.haomeiwen.com/subject/kchsrftx.html