CopyOnWriteArray的使用

由于之前在弄 eventbus的源码分析时,源码中有用到CopyOnWriteArray 由于时间问题,知道现在才做了一个相应的整理:

---------------------------------------------------------做一枚健康的小码畜--------------------------------------------------

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

在源码中可以看到:

1 public CopyOnWriteArrayList(Collection<? extends E> c) {
2         Object[] elements = c.toArray();
3         // c.toArray might (incorrectly) not return Object[] (see 6260652)
4         if (elements.getClass() != Object[].class)               //这里是copyof,
5             elements = Arrays.copyOf(elements, elements.length, Object[].class);
6         setArray(elements);
7     }

CopyOnWriteArrayList 其实是做了一份拷贝,所以一般需要很大的开销,在android中不建议将context或者activity放到CopyOnWriteArrayList中

尽管需要很大的开销,但是当遍历操作的数量大大超过可变操作的数量时,这种方法可能比其他替代方法 有效。在不能或不想进行同步遍历,但又需要从并发线程中排除冲突时,它也很有用。“快照”风格的迭代器方法在创建迭代器时使用了对数组状态的引用。此数组在迭代器的生存期内不会更改,因此不可能发生冲突,并且迭代器保证不会抛出ConcurrentModificationException。创建迭代器以后,迭代器就不会反映列表的添加、移除或者更改。在迭代器上进行的元素更改操作(remove、set和add)不受支持。这些方法将抛出UnsupportedOperationException。允许使用所有元素,包括null。

在CopyOnWriteArrayList里处理写操作(包括add、remove、set等)是先将原始的数据通过JDK1.6的Arrays.copyof()来生成一份新的数组

然后在新的数据对象上进行写,写完后再将原来的引用指向到当前这个数据对象,这样保证了每次写都是在新的对象上(因为要保证写的一致性,这里要对各种写操作要加一把锁,JDK1.6在这里用了重入锁),

然后读的时候就是在引用的当前对象上进行读(包括get,iterator等),不存在加锁和阻塞,针对iterator使用了一个叫 COWIterator的阉割版迭代器,因为不支持写操作,当获取CopyOnWriteArrayList的迭代器时,是将迭代器里的数据引用指向当前 引用指向的数据对象,无论未来发生什么写操作,都不会再更改迭代器里的数据对象引用,所以迭代器也很安全。

CopyOnWriteArrayList中写操作需要大面积复制数组,所以性能肯定很差,但是读操作因为操作的对象和写操作不是同一个对象,读之 间也不需要加锁,读和写之间的同步处理只是在写完后通过一个简单的“=”将引用指向新的数组对象上来,这个几乎不需要时间,这样读操作就很快很安全,适合 在多线程里使用,绝对不会发生ConcurrentModificationException ,所以最后得出结论:CopyOnWriteArrayList适合使用在读操作远远大于写操作的场景里,比如缓存。

内存一致性效果:当存在其他并发 collection 时,将对象放入CopyOnWriteArrayList之前的线程中的操作 happen-before 随后通过另一线程从CopyOnWriteArrayList中访问或移除该元素的操作。

这种情况一般在多线程操作时,一个线程对list进行修改。一个线程对list进行fore时会出现java.util.ConcurrentModificationException错误。

比如:两个线程一个线程fore一个线程修改list的值。

时间: 2025-01-11 18:22:44

CopyOnWriteArray的使用的相关文章

copyOnWriteArray 并发包下的不安全(数组)集合

copyOnWriteArray  记录一下 package java.util.concurrent;//你没有看错,是这个包 private transient volatile Object[] array;//初始化数组 public CopyOnWriteArrayList() {//构造函数,初始化 setArray(new Object[0]); } final void setArray(Object[] a) { array = a; } public boolean add(

笔记:java并发编程实践1

Java 5.0 adds ConcurrentHashMap, a replacement for synchronized hash-based Map implementations, and CopyOnWriteArrayList, a replacement for synchronized List implementations for cases where traversal is the dominant operation. The new ConcurrentMap i

面经 收藏的 这可能不只是一篇面经

作者:_XiaoTeng_链接:https://www.nowcoder.com/discuss/29890来源:牛客网 写了个显眼的标题,就真得说几句有用的话. 5月份一个很偶然的机会,加了叶神的微信,还收到了祝福.一激动就承诺说写篇最详细的面经分享给大家,毕竟用了这么久的牛客网,收获真的很大. 校招真的是段劳心伤神的经历,我把这一路的体会,写在秋招前,也许能给那些和我一样迷茫过,怀疑过,失落过的人一些帮助. (这篇文章有点长,可能需要点耐心) 0. 写在之前 首先呢我的面试经历和一些面霸和收

设计模式:观察者模式--Observer

一.什么是观察者模式 1.生活中的观察者模式 1.警察抓小偷 在现实生活中,警察抓小偷是一个典型的观察者模式「这以一个惯犯在街道逛街然后被抓为例子」,这里小偷就是被观察者,各个干警就是观察者,干警时时观察着小偷,当小偷正在偷东西「就给干警发送出一条信号,实际上小偷不可能告诉干警我有偷东西」,干警收到信号,出击抓小偷.这就是一个观察者模式 2.装模作样写作业 小时候家里家活比较多,爸妈让我去干活的时候,我偶尔会说我要学习「其实不想去干活,当然只是偶尔,我还是常常干家务的」,然后爸妈就去地里了,我一

【详解】CopyOnWriteArrayList

前言 之前看<Java并发编程>这本书的时候,有看到这个,只记得"读多写少"."写入时复制".书中没有过多讲述,只是一笔带过(不过现在回头看,发现讲的都是精髓.老外的书大多重理论,喜欢花大篇幅讲概念,这点我非常喜欢)记得当时是觉得可能有点难,先跳过了,结果就忘记回头看了.今天突然想起来,就看了一下,整理一点东西. 非线程安全的ArrayList 我们知道原来util包中的ArrayList是不提供同步的,也就是说当多个线程读写ArrayList的时候可能

深入浅出Tomcat/3 - Tomcat生命周期

在上面的部分,其实我们已经接触到Tomcat的生命周期了,接下来我们将仔细讨论和学习Tomcat的生命周期的具体实现. LifeCycle接口 这个LifeCycle接口上面在讲解Server和Service时其实已经有所接触.Tomcat通过org.apache.catalina.LifeCycle接口统一接管Tomcat的生命周期,所有继承自它的组件(即Component)都需要实现这个接口. 我们先俯视看一看LifeCycle接口的定义. 根据上图,我们清晰看到上图包含了4个生命周期的方法

一篇面经(BAT面试)(转)

0. 写在之前 首先呢我的面试经历和一些面霸和收割机的大神相比绝不算丰富,但我这三个月应该能代表很大一部分人的心路历程:从无忧无虑也无知的状态,然后遭遇挫败,跌入低谷,连续数天的黑暗,慢慢调整,逼着自己不能松懈,看到改变,收获肯定,分享经历. 先大概说下自己的面试经历吧(详细的面试过程和面试题解析在最后): 相关的公司有四类: 笔试就挂了的:网易.头条.(对于笔试这个东西我到现在都没太多经验) 网易是第一家参加笔试的,面试会报销费用去总部,所以还是有难度,这个公司呢,内推不内推都要参加笔试.所以