证明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;}@Overridepublic 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;}@Overridepublic 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、初始化CopyOnWriteArrayListList<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复制代码

说明了CopyOnWriteArrayList并发多线程的环境下,仍然能很好的工作。


CopyOnWriteArrayList如何做到线程安全的


CopyOnWriteArrayList使用了一种叫写时复制的方法,当有新元素添加到CopyOnWriteArrayList时,先从原有的数组中拷贝一份出来,然后在新的数组做写操作,写完之后,再将原来的数组引用指向到新数组。

当有新元素加入的时候,如下图,创建新数组,并往新数组中加入一个新元素,这个时候,array这个引用仍然是指向原数组的。

这里写图片描述

当元素在新数组添加成功后,将array这个引用指向新数组。

这里写图片描述

CopyOnWriteArrayList的整个add操作都是在的保护下进行的。
这样做是为了避免在多线程并发add的时候,复制出多个副本出来,把数据搞乱了,导致最终的数组数据不是我们期望的。

CopyOnWriteArrayListadd操作的源代码如下:

 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、使用另外开辟空间的思路,来解决并发冲突


原文链接


  • 线程安全的CopyOnWriteArrayList介绍

线程安全的CopyOnWriteArrayList介绍相关推荐

  1. (转)线程安全的CopyOnWriteArrayList介绍

    转载自:线程安全的CopyOnWriteArrayList介绍 证明CopyOnWriteArrayList是线程安全的 先写一段代码证明CopyOnWriteArrayList确实是线程安全的. 读 ...

  2. Java自带的线程池ThreadPoolExecutor详细介绍说明和实例运用

    Java 5 开始,Java 提供了自己的线程池.线程池就是一个线程的容器,每次只执行额定数量的线程. java.util.concurrent.ThreadPoolExecutor 就是这样的线程池 ...

  3. 创建线程:pthread_creat() 函数介绍

    创建线程:pthread_creat() 函数介绍 语法 : int pthread_creat(pthread_t *thread,const pthread_attr_t *attr,void * ...

  4. JDK1.8源码分析:线程安全的CopyOnWriteArrayList与CopyOnWriteArraySet

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 作者:服务端开发 blog.csdn.net/u01001 ...

  5. java 线程简介_java多线程介绍

    java多线程介绍 多线程的基本实现 进程指运行中的程序,每个进程都会分配一个内存空间,一个进程中存在多个线程,启动一个JAVA虚拟机,就是打开个一个进程,一个进程有多个线程,当多个线程同时进行,就叫 ...

  6. 进程与线程的关系简单介绍

    文章目录 1. 进程与线程的简单介绍 2. 进程 基本特点: 3. 线程 1. 进程与线程的简单介绍   什么是进程?打个比方,你的程序要执行,操作系统就会杷你的exe文件加载到内存中.那就生成一个进 ...

  7. 线程安全的CopyOnWriteArrayList集合

    CopyOnWriteArrayList 读取和写入源码简单分析(java.util.concurrent包下) 1. CopyOnWriteArrayList 读取操作的实现 读取操作没有任何同步控 ...

  8. 线程本地ThreadLocal的介绍与使用!

    ThreadLocal简介 我们通过上两篇的学习,我们已经知道了变量值的共享可以使用public static变量的形式,所有的线程都使用同一个被public static修饰的变量. 那么如果我们想 ...

  9. 自定义线程池-线程池工作流程介绍

    ThreadPoolExecutor参数详解 我们可以通过下面的场景理解ThreadPoolExecutor中的各个参数; a客户(任务)去银行(线程池)办理业务,但银行刚开始营业,窗口服务员还未就位 ...

最新文章

  1. 手动部署OpenStack环境(二:CentOS6.6虚拟机的安装及配置)
  2. WinAPI: Arc - 绘制弧线
  3. 数据库事务原理及并发、死锁
  4. 十、【栈和队列】队列
  5. DCT算法的原理及实现简介
  6. jenkins测试c语言接口,Jenkins集成接口测试实践(一)
  7. JQuery中this指向
  8. 中国恒大:正接触独立第三方投资者
  9. APP运营者如何对用户的数据进行分析?
  10. mysql安装 2018最新安装mysql教程及遇到的问题解决Windows下
  11. python自动化办公都能做什么-用 Python 自动化办公能做到哪些有趣或有用的事情?...
  12. 专线维护 07/11
  13. JavaWeb播放视频实现断点续传、分片上传
  14. 常用#免费%代理IP库整理*收藏——实时@更新(大概)
  15. 在vue中使用html表格
  16. Codeforces 474B. Worms
  17. 谷歌字典mac客户端
  18. 美国卡尔顿学院计算机专业怎么样,美国留学,选择卡尔顿学院好么?
  19. Android渠道推广方案相关知识收集
  20. 怎么网站服务器退出全屏,退出Hyper V客户端的全屏模式

热门文章

  1. string是python内置函数吗_Python 字符串与内置函数(方法)
  2. git21天打卡day18-新建远程仓库
  3. Fiddler显示只抓取特定网站或APP
  4. java技术不行有复试怎么办_复试答不上来怎么办?记住这四点不慌!
  5. matlab 非线性电感,基于Matlab/Simulink利用动态和静态电感等磁参数建立了一种开关磁阻电机的非线性磁参数模型...
  6. github 搜索_如何通过GitHub快速的搜索资源?
  7. graph面板x轴模式包括哪些_激光五轴加工机床技术参数有哪些?
  8. mysql 锁怎么使用_MySQL锁的用法之行级锁
  9. 优化函数、学习速率 与反向传播算法
  10. Pytorch基础(二) 初始自动微分