zoukankan      html  css  js  c++  java
  • CopyOnWriteArrayList总结

    一:使用场景
    CopyOnWriteArrayList适用于场景为读多写少的集合应用场景中。

    二:CopyOnWrite容器
    CopyOnWrite容器即写时复制的容器。通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。

    三:CopyOnWriteArrayList的实现原理

    源码如下所示: 

     1     public boolean add(E e) {
     2         final ReentrantLock lock = this.lock;
     3         lock.lock();
     4         try {
     5             Object[] elements = getArray();
     6             int len = elements.length;
     7             Object[] newElements = Arrays.copyOf(elements, len + 1);
     8             newElements[len] = e;
     9             setArray(newElements);
    10             return true;
    11         } finally {
    12             lock.unlock();
    13         }
    14     }
    15 
    16     public E remove(int index) {
    17         final ReentrantLock lock = this.lock;
    18         lock.lock();
    19         try {
    20             Object[] elements = getArray();
    21             int len = elements.length;
    22             E oldValue = get(elements, index);
    23             int numMoved = len - index - 1;
    24             if (numMoved == 0)
    25                 setArray(Arrays.copyOf(elements, len - 1));
    26             else {
    27                 Object[] newElements = new Object[len - 1];
    28                 System.arraycopy(elements, 0, newElements, 0, index);
    29                 System.arraycopy(elements, index + 1, newElements, index,
    30                                  numMoved);
    31                 setArray(newElements);
    32             }
    33             return oldValue;
    34         } finally {
    35             lock.unlock();
    36         }
    37     }
    38 
    39     public E set(int index, E element) {
    40         final ReentrantLock lock = this.lock;
    41         lock.lock();
    42         try {
    43             Object[] elements = getArray();
    44             E oldValue = get(elements, index);
    45 
    46             if (oldValue != element) {
    47                 int len = elements.length;
    48                 Object[] newElements = Arrays.copyOf(elements, len);
    49                 newElements[index] = element;
    50                 setArray(newElements);
    51             } else {
    52                 // Not quite a no-op; ensures volatile write semantics
    53                 setArray(elements);
    54             }
    55             return oldValue;
    56         } finally {
    57             lock.unlock();
    58         }
    59     }

     该集合对写操作实现了加锁操作,对读操作没有实现加锁,读操作源码如下所示:

    1     private E get(Object[] a, int index) {
    2         return (E) a[index];
    3     }
    1     /** The array, accessed only via getArray/setArray. */
    2     private transient volatile Object[] array;

    其实经过源码分析之后,我们发现把元素存储到一个全局的数组里面,该数据是使用volatile关键字进行修饰的,这样其实我们已经理解了其中的原理,就是使用volatile的可见性。

    四:CopyOnWriteArrayList的优缺点

    CopyOnWrite容器有很多优点,但是同时也存在两个问题,即内存占用问题和数据一致性问题。所以在开发的时候需要注意一下。

    ①:内存占用问题。因为CopyOnWrite的写时复制机制,所以在进行写操作的时候,内存里会同时驻扎两个对象的内存,旧的对象和新写入的对象(注意:在复制的时候只是复制容器里的引用,只是在写的时候会创建新对象添加到新容器里,而旧容器的对象还在使用,所以有两份对象内存)。

    ②:数据一致性问题。CopyOnWrite容器只能保证数据的最终一致性,不能保证数据的实时一致性。因为复制和操作元素需要一点儿时间,所以会有延迟,所以如果你希望写入的数据,马上能读到,要求数据强一致性的话,请不要使用CopyOnWrite容器。【当执行add或remove操作没完成时,get获取的仍然是旧数组的元素】

  • 相关阅读:
    局域网组网总目录
    VLAN之间的通信
    DHCP
    ACL
    linux 程序后台运行
    VLAN
    VTP
    dubbox生产者与消费者案例
    String data jpa执行的增删改查
    StringBoot整合Mytais实现数据查询与分页
  • 原文地址:https://www.cnblogs.com/jelly12345/p/14074206.html
Copyright © 2011-2022 走看看