zoukankan      html  css  js  c++  java
  • CopyOnWriteArrayList

            CopyOnWriteArrayList类最大的特点就是,在对其实例进行修改操作(add/remove等)会新建一个数据并修改,修改完毕之后,再将原来的引用指向新的数组。这样,修改过程没有修改原来的数组。也就没有了ConcurrentModificationException错误。
            从上面的结果很容易就看出来,hashcode变化了多次,说明了list已经不是原来的list对象了。这说明了CopyOnWriteArrayList类的add函数在执行的时候确实是修改了list的数组对象。
     

    add函数

     
        1. /** 
        2.      * Appends the specified element to the end of this list. 
        3.      * 
        4.      * @param e element to be appended to this list 
        5.      * @return <tt>true</tt> (as specified by {@link Collection#add}) 
        6.      */  
        7.     public boolean add(E e) {  
        8.     final ReentrantLock lock = this.lock;  
        9.     lock.lock();  
        10.     try {  
        11.         Object[] elements = getArray();  
        12.         int len = elements.length;  
        13.         Object[] newElements = Arrays.copyOf(elements, len + 1);  
        14.         newElements[len] = e;  
        15.         setArray(newElements);  
        16.         return true;  
        17.     } finally {  
        18.         lock.unlock();  
        19.     }  
        20.     }  
     
    add函数中拷贝了原来的数组并在最后加上了新元素。然后调用setArray函数将引用链接到新数组
        1. /** 
        2.     * Sets the array. 
        3.     */  
        4.    final void setArray(Object[] a) {  
        5.        array = a;  
        6.    } 
     
     
     

            CopyOnWriteArrayList是ArrayList 的一个线程安全的变体,其中所有可变操作(add、set等等)都是通过对底层数组进行一次新的复制来实现的。

            这一般需要很大的开销,但是当遍历操作的数量大大超过可变操作的数量时,这种方法可能比其他替代方法 有效。在不能或不想进行同步遍历,但又需要从并发线程中排除冲突时,它也很有用。

            “快照”风格的迭代器方法在创建迭代器时使用了对数组状态的引用。此数组在迭代器的生存期内不会更改,因此不可能发生冲突,并且迭代器保证不会抛出ConcurrentModificationException。

            创建迭代器以后,迭代器就不会反映列表的添加、移除或者更改。

            在迭代器上进行的元素更改操作(remove、set和add)不受支持。这些方法将抛出UnsupportedOperationException。允许使用所有元素,包括null。

     
     

    这个类和ArrayList最大的区别就是add(E) 的时候。容器会自动copy一份出来然后再尾部add(E)。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    /**
        * Appends the specified element to the end of this list.
        *
        * @param e element to be appended to this list
        * @return <tt>true</tt> (as specified by {@link Collection#add})
        */
       publicbooleanadd(E e) {
       finalReentrantLock lock = this.lock;
       lock.lock();
       try{
           Object[] elements = getArray();
           intlen = elements.length;
           Object[] newElements = Arrays.copyOf(elements, len + 1);
           newElements[len] = e;
           setArray(newElements);
           returntrue;
       finally{
           lock.unlock();
       }
       }
     
     
     
            CopyOnWriteArrayList add(E) 和remove(int index)都是对新的数组进行修改和新增。所以在多线程操作时不会出现java.util.ConcurrentModificationException错误。

    总结

    CopyOnWriteArrayList适合使用在读操作远远大于写操作的场景里,比如缓存。
            发生修改时候做copy,新老版本分离,保证读的高性能,适用于以读为主的情况
  • 相关阅读:
    linux查看CPU和内存信息
    linux yum命令详解
    查看文件中关键字前后几行的内容
    vue.js+web storm安装及第一个vue.js
    android GPS: code should explicitly check to see if permission is available
    ASP.NET MVC Identity 使用自己的SQL Server数据库
    阿里云服务器,tomcat启动,一直卡在At least one JAR was scanned for TLDs yet contained no TLDs就不动了
    ASP.NET MVC4 MVC 当前上下文中不存在名称“Scripts”
    python 将windows字体中的汉字生成图片的方法
    Java android DES+Base64加密解密
  • 原文地址:https://www.cnblogs.com/lsx1993/p/4619963.html
Copyright © 2011-2022 走看看