转载自:线程安全的CopyOnWriteArrayList介绍

证明CopyOnWriteArrayList是线程安全的

先写一段代码证明CopyOnWriteArrayList确实是线程安全的。

读线程

写线程

测试代码

运行上面的代码,没有报出

java.util.ConcurrentModificationException

1

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

CopyOnWriteArrayList如何做到线程安全的

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

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

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

CopyOnWriteArrayList的整个add操作都是在的保护下进行的。

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

CopyOnWriteArrayList的add操作的源代码如下:

publicbooleanadd(E e) {//1、先加锁final ReentrantLocklock=this.lock;lock.lock();try{        Object[] elements = getArray();intlen = elements.length;//2、拷贝数组Object[] newElements = Arrays.copyOf(elements, len +1);//3、将元素加入到新数组中newElements[len] = e;//4、将array引用指向到新数组setArray(newElements);returntrue;    }finally{//5、解锁lock.unlock();    }}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

由于所有的写操作都是在新数组进行的,这个时候如果有线程并发的写,则通过锁来控制,如果有线程并发的读,则分几种情况:

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容器

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

  1. 线程安全的CopyOnWriteArrayList介绍

    证明CopyOnWriteArrayList是线程安全的 先写一段代码证明CopyOnWriteArrayList确实是线程安全的. ReadThread.java import java.util. ...

  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. php tp5路由教程,附件八 TP5路由设置源码
  2. hurst代码 python_python数据类型—字符串
  3. python爬虫系列之数据的存储(二):csv库的使用
  4. Ivan and Powers of Two CodeForces - 305C(set)
  5. Mongodb 分片与副本集
  6. 案例 体检套餐管理系统 需求一览 c# 1614099219
  7. android.mk 编译jar包,Androidmk 使用详解
  8. JavaScript中执行环境和栈
  9. Navicat MySQL连接Linux下MySQL的及2003错误解决方案
  10. java输出各国人的问候语_世界各国问候语及发音.doc
  11. 如何在正则表达式中使用变量?
  12. IDEA 导入项目 导入不进去
  13. andorid studio 无法识别app项目解决
  14. 网络带宽单位转换 — MB/s、Mb/s、Mbps、Mbit/s、Kbps
  15. 树莓派/linux 功能配置(含网络)不定期更新
  16. java interop,服务器程序的Xamarin-Java.Interop体验(一)
  17. 3.6 Meterpreter 键盘记录
  18. 使用电子签章确立区块链电子发票的法律效力
  19. 四、微信小程序之简单计算器(学习记录)
  20. (C语言)猜数字游戏,猜中负数,直接游戏结束,一次猜中,bingo,1~3次,Lucky you!......

热门文章

  1. 养成一个新习惯,只需要这个大脑区域兴奋0.5秒
  2. 2019年大数据发展将走向何方
  3. 深度学习在推荐系统上的应用
  4. 普华永道:人工智能将重塑职位格局并与物联网合并
  5. 中国研制出首款搭载寒武纪AI芯片的人工智能服务器
  6. 为什么我们很难看到代码 5 分钟前的样子?
  7. 开玩笑写代码获奥斯卡?计算机图形专家这样 5 次捧回大奖!
  8. 没有 5G 版 iPhone 的苹果秋季发布会,发布了些什么?
  9. 大一就会这么多,还在问有没有前途? | 每日趣闻
  10. 厉害!国内大学生计算机编程第一人,一人挑战一个队,百度最年轻 T10,现创业自动驾驶...