线程安全的CopyOnWriteArrayList
证明CopyOnWriteArrayList是线程安全的
先写一段代码证明CopyOnWriteArrayList确实是线程安全的。
ReadThread.java
import java.util.List;
public class ReadThread implements Runnable {
private List<Integer> list;
public ReadThread(List<Integer> list) {
this.list = list;
}
@Override
public void run() {
for (Integer ele : list) {
System.out.println("ReadThread:"+ele);
}
}
}
WriteThread.java
import java.util.List;
public class WriteThread implements Runnable {
private List<Integer> list;
public WriteThread(List<Integer> list) {
this.list = list;
}
@Override
public void run() {
this.list.add(9);
}
}
TestCopyOnWriteArrayList.java
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class TestCopyOnWriteArrayList {
private void test() {
//1、初始化CopyOnWriteArrayList
List<Integer> tempList = Arrays.asList(new Integer [] {1,2});
CopyOnWriteArrayList<Integer> copyList = new CopyOnWriteArrayList<>(tempList);
//2、模拟多线程对list进行读和写
ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.execute(new ReadThread(copyList));
executorService.execute(new WriteThread(copyList));
executorService.execute(new WriteThread(copyList));
executorService.execute(new WriteThread(copyList));
executorService.execute(new ReadThread(copyList));
executorService.execute(new WriteThread(copyList));
executorService.execute(new ReadThread(copyList));
executorService.execute(new WriteThread(copyList));
System.out.println("copyList size:"+copyList.size());
}
public static void main(String[] args) {
new TestCopyOnWriteArrayList().test();
}
}
运行上面的代码,没有报出
java.util.ConcurrentModificationException
1
说明了CopyOnWriteArrayList并发多线程的环境下,仍然能很好的工作。
CopyOnWriteArrayList如何做到线程安全的
CopyOnWriteArrayList使用了一种叫写时复制的方法,当有新元素添加到CopyOnWriteArrayList时,先从原有的数组中拷贝一份出来,然后在新的数组做写操作,写完之后,再将原来的数组引用指向到新数组。
当有新元素加入的时候,如下图,创建新数组,并往新数组中加入一个新元素,这个时候,array这个引用仍然是指向原数组的。
当元素在新数组添加成功后,将array这个引用指向新数组。
CopyOnWriteArrayList的整个add操作都是在锁的保护下进行的。
这样做是为了避免在多线程并发add的时候,复制出多个副本出来,把数据搞乱了,导致最终的数组数据不是我们期望的。
CopyOnWriteArrayList的add操作的源代码如下:
public boolean add(E e) {
//1、先加锁
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
//2、拷贝数组
Object[] newElements = Arrays.copyOf(elements, len + 1);
//3、将元素加入到新数组中
newElements[len] = e;
//4、将array引用指向到新数组
setArray(newElements);
return true;
} finally {
//5、解锁
lock.unlock();
}
}
由于所有的写操作都是在新数组进行的,这个时候如果有线程并发的写,则通过锁来控制,如果有线程并发的读,则分几种情况:
1、如果写操作未完成,那么直接读取原数组的数据;
2、如果写操作完成,但是引用还未指向新数组,那么也是读取原数组数据;
3、如果写操作完成,并且引用已经指向了新的数组,那么直接从新数组中读取数据。
可见,CopyOnWriteArrayList的读操作是可以不用加锁的。
CopyOnWriteArrayList的使用场景
通过上面的分析,CopyOnWriteArrayList 有几个缺点:
1、由于写操作的时候,需要拷贝数组,会消耗内存,如果原数组的内容比较多的情况下,可能导致young gc或者full gc
2、不能用于实时读的场景,像拷贝数组、新增元素都需要时间,所以调用一个set操作后,读取到数据可能还是旧的,虽然CopyOnWriteArrayList 能做到最终一致性,但是还是没法满足实时性要求;
CopyOnWriteArrayList 合适读多写少的场景,不过这类慎用
因为谁也没法保证CopyOnWriteArrayList 到底要放置多少数据,万一数据稍微有点多,每次add/set都要重新复制数组,这个代价实在太高昂了。在高性能的互联网应用中,这种操作分分钟引起故障。
CopyOnWriteArrayList透露的思想
如上面的分析CopyOnWriteArrayList表达的一些思想:
1、读写分离,读和写分开
2、最终一致性
3、使用另外开辟空间的思路,来解决并发冲突
参考的文章
JAVA中的COPYONWRITE容器
---------------------
作者:Sam哥哥
来源:CSDN
原文:https://blog.csdn.net/linsongbin1/article/details/54581787
版权声明:本文为博主原创文章,转载请附上博文链接!
https://coolshell.cn/articles/11175.html
线程安全的CopyOnWriteArrayList的更多相关文章
- 线程安全的CopyOnWriteArrayList介绍
证明CopyOnWriteArrayList是线程安全的 先写一段代码证明CopyOnWriteArrayList确实是线程安全的. ReadThread.java import java.util. ...
- CopyOnWriteArrayList真的完全线程安全吗
我之前书上看到的说法是:Vector是相对线程安全,CopyOnWriteArrayList是绝对线程安全 这种说法其实有些问题,CopyOnWriteArrayList在某些场景下还是会报错的 Co ...
- Java并发编程:并发容器之CopyOnWriteArrayList(转载)
Java并发编程:并发容器之CopyOnWriteArrayList(转载) 原文链接: http://ifeve.com/java-copy-on-write/ Copy-On-Write简称COW ...
- Java并发编程:并发容器之CopyOnWriteArrayList
转载: Java并发编程:并发容器之CopyOnWriteArrayList Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个 ...
- 并发容器之CopyOnWriteArrayList
原文链接: http://ifeve.com/java-copy-on-write/ Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容 ...
- 【多线程】Java并发编程:并发容器之CopyOnWriteArrayList(转载)
原文链接: http://ifeve.com/java-copy-on-write/ Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容 ...
- 并发容器之CopyOnWriteArrayList(转载)
Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改, ...
- (转)Java并发编程:并发容器之CopyOnWriteArrayList
原文链接:http://ifeve.com/java-copy-on-write/ Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容, ...
- 并发容器之CopyOnWriteArrayList(转载)
Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这 个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改 ...
随机推荐
- django基础-02:虚拟环境
4. 虚拟环境 4.1 概念 之前安装python包的命令: sudo pip3 install 包名 包的安装路径:/usr/local/lib/python3.5/dist-packages 在同 ...
- XtraBackup之踩过的坑
xtrabackup相信目前使用已经非常广泛了,备份innodb表的首选工具,但是其中还是有点小坑,虽然发生的概率不大,但是我还是踩坑了.关于xtrabackup的详细参考请查阅官方文档http:// ...
- MySQL 5.6 Index Condition Pushdown
ICP(index condition pushdown)是mysql利用索引(二级索引)元组和筛字段在索引中的where条件从表中提取数据记录的一种优化操作.ICP的思想是:存储引擎在访问索引的时候 ...
- what's the python之模块
正则表达式 首先,我们引入了正则表达式的知识.所谓正则表达式,就是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符.及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对 ...
- GitHub账户注册
GitHub是一个优秀的面向开源及私有软件项目的托管平台,值得我们使用,但因为其不同于我们常见的很多平台,所以刚开始使用时,我们会遇到很多的问题.特此记录下博主自己使用GitHub的过程供自己以后查看 ...
- linux上pem格式私钥转pfx格式证书的命令
1.root.csr 可改成其它名字,后缀名不改 openssl req -new -key 私钥名称.pem -out root.csr 2.root.crt 可改成其它名字,后缀名不改 opens ...
- [LeetCode] 584. Find Customer Referee_Easy tag: SQL
Given a table customer holding customers information and the referee. +------+------+-----------+ | ...
- idc交叉引用
#查找所有调用MSHookFunction的地方 ea=LocByName("MSHookFunction") if None !=ea: refs = idautils.Code ...
- Python基础(四) socket简单通讯
socket:我们通常听过的套接字: 服务端: 1.创建socket对象 2.bing 绑定ip及端口 3.对该端口进行监听 4.消息阻塞(等待客户端消息) 客户端: 1.创建socket对象 2.连 ...
- PHP json_encode/json_decode与serialize/unserializ性能测
PHP里面,有时候出于实际需求考虑,需要将某些信息以数组的方式进行存储,甚至有时候介于数组.字符串两者之间,很难确定是数组还是字符串,如果最终还需要将这些信息存储到文件系统中,而且要保证正确无误的存储 ...