`

CopyOnWriteArrayList

阅读更多
CopyOnWriteArrayList


源码解析转载自:https://www.cnblogs.com/leesf456/p/5547853.html
总结:
1:线程安全,读操作时无锁,相当于的ArrayList。
2:底层数据结构是一个Object[],初始容量为0,之后每增加一个元素,容量+1,数组复制一遍。
3:增删改上锁、读不上锁。
4:遍历过程由于遍历的只是全局数组的一个副本,即使全局数组发生了增删改变化,副本也不会变化,所以不会发生并发异常(concurrentModificationException)。(即当一个集合进行遍历的时候,同时对集合进行增删改,不会发生并发异常。例如ArrayList会发生该问题)
5:读多写少且脏数据影响不大的并发情况下,选择CopyOnWriteArrayList。

question1:get(int)操作会发生脏读,为什么?
一个线程正在进行对集合的添加,此时会copy一个数组的副本进行处理,当写入完毕之后,会将引用从原数组指向新数组。若在引用的指向过程中,即操作add的线程还未进行指向新数据之前,此时另外一个线程进行对集合的get操作(读操作),则此时会发生脏读。

Copy-On-Write容器介绍转载自:http://ifeve.com/java-copy-on-write/
使用CopyOnWriteArrayList需要注意两件事情:
1:减少初始化扩容开销。根据实际需要,初始化CopyOnWriteArrayList的大小,避免第一次写时CopyOnWriteArrayList扩容的开销。 
2:使用批量添加。因为每次添加,容器每次都会进行复制,所以减少添加次数,可以减少容器的复制次数。如使用上面代码里的addBlackList方法。

Copy-On-Write容器缺点:
1:内存占用问题。因为增删改数据时,会复制一个副本进行处理。内存中会存在两份,造成内存开销。
2:数据一致性问题。CopyOnWrite容器只能保证数据的最终一致性,不能保证数据的实时一致性。所以如果你希望写入的的数据,马上能读到,请不要使用CopyOnWrite容器。

Collections.synchronizedList(ArrayList)。将ArrayList变成线程安全的类,即将该类+synchronized同步关键字进行处理。
Collections里面的synchronizedList的源码:
public static <T> List<T> synchronizedList(List<T> list) {  
    return (list instanceof RandomAccess ?  
               new SynchronizedRandomAccessList<T>(list) :  
               new SynchronizedList<T>(list));//根据不同的list类型最终实现不同的包装类。  
   }  
static class SynchronizedList<E>
        extends SynchronizedCollection<E>
        implements List<E> {
        private static final long serialVersionUID = -7754090372962971524L;

        final List<E> list;

        SynchronizedList(List<E> list) {//new SynchronizedList<T>(list))指向的 方法
            super(list);
            this.list = list;
        }

Collections.synchronizedList(ArrayList)和CopyOnWriteArrayList比较:
转载自:https://www.cnblogs.com/yan456jie/p/5369366.html
        CopyOnWriteArrayList和Collections.synchronizedList(ArrayList)是实现线程安全的列表的两种方式。两种实现方式分别针对不同情况有不同的性能表现,其中CopyOnWriteArrayList的写操作性能较差,而多线程的读操作性能较好。而Collections.synchronizedList的写操作性能比CopyOnWriteArrayList在多线程操作的情况下要好很多,而读操作因为是采用了synchronized关键字的方式,其读操作性能并不如CopyOnWriteArrayList。因此在不同的应用场景下,应该选择不同的多线程安全实现类。
        CopyOnWriteArrayList,发生修改时候做copy,新老版本分离,保证读的高性能,适用于以读为主,读操作远远大于写操作的场景中使用,比如缓存。而Collections.synchronizedList则可以用在CopyOnWriteArrayList不适用,但是有需要同步列表的地方,读写操作都比较均匀的地方。

Collections.SynchronizedList(ArrayList)和Vector的区别:
转载自:http://blog.csdn.net/dviewer/article/details/52970896
1:SynchronizedList有很好的扩展和兼容功能。他可以将所有的List的子类转成线程安全的类。
(若当SynchronizedList包装ArrayList时,ArrayList变成线程安全的类,但是扩容机制和Vector不同,SynchronizedList(ArrayList)和ArrayList的扩容机制相同)
2:使用SynchronizedList的时候,进行遍历时要手动进行同步处理。并没有对interator( )方法+synchronized同步关键字。
官方文档解释例子:
        List list = Collections.synchronizedList(new ArrayList());
         ...
        synchronized (list) {
            Iterator i = list.iterator(); // Must be in synchronized block
            while (i.hasNext())
                i.next();
        }

3:SynchronizedList可以指定锁定的对象。SynchronizedList使用的synchronized同步代码块,Vector使用的是synchronized同步方法,同步代码块的同步粒度更小,效率更高。

补充:同步代码块和同步方法的区别: 
1:同步代码块在锁定的范围上可能比同步方法要小,一般来说锁的范围大小和性能是成反比的。 ---同步代码块性能更好
2:同步块可以更加精确的控制锁的作用域(锁的作用域就是从锁被获取到其被释放的时间),同步方法的锁的作用域就是整个方法。
3:静态代码块可以选择对哪个对象加锁,但是静态方法只能给this对象加锁。

CopyOnWriteArrayList和CopyOnWriteArraySet的区别:
就是相当于list和set的区别。list可以允许重复,set不允许重复。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics