Java并发编程实战~并发容器

在容器领域一个容易被忽视的“坑”是用迭代器遍历容器,例如在下面的代码中,通过迭代器遍历容器 list,对每个元素调用 foo() 方法,这就存在并发问题,这些组合的操作不具备原子性。

List list = Collections.synchronizedList(new ArrayList());
Iterator i = list.iterator(); 
while (i.hasNext())foo(i.next());

正确做法是下面这样,锁住 list 之后再执行遍历操作

List list = Collections.synchronizedList(new ArrayList());
synchronized (list) {  Iterator i = list.iterator(); while (i.hasNext())foo(i.next());
} 

发容器及其注意事项
Java 在 1.5 版本之前所谓的线程安全的容器,主要指的就是同步容器。不过同步容器有个最大的问题,那就是性能差,所有方法都用 synchronized 来保证互斥,串行度太高了。因此 Java 在 1.5 及之后版本提供了性能更高的容器,我们一般称为并发容器。

并发容器虽然数量非常多,但依然是前面我们提到的四大类:List、Map、Set 和 Queue,下面的并发容器关系图,基本上把我们经常用的容器都覆盖到了。

 鉴于并发容器的数量太多,再加上篇幅限制,所以我并不会一一详细介绍它们的用法,只是把关键点介绍一下。

(一)List
List 里面只有一个实现类就是CopyOnWriteArrayList。CopyOnWrite,顾名思义就是写的时候会将共享变量新复制一份出来,这样做的好处是读操作完全无锁。

那 CopyOnWriteArrayList 的实现原理是怎样的呢?下面我们就来简单介绍一下

CopyOnWriteArrayList 内部维护了一个数组,成员变量 array 就指向这个内部数组,所有的读操作都是基于 array 进行的,如下图所示,迭代器 Iterator 遍历的就是 array 数组。

 如果在遍历 array 的同时,还有一个写操作,例如增加元素,CopyOnWriteArrayList 是如何处理的呢?CopyOnWriteArrayList 会将 array 复制一份,然后在新复制处理的数组上执行增加元素的操作,执行完之后再将 array 指向这个新的数组。通过下图你可以看到,读写是可以并行的,遍历操作一直都是基于原 array 执行,而写操作则是基于新 array 进行。

 使用 CopyOnWriteArrayList 需要注意的“坑”主要有两个方面。一个是应用场景,CopyOnWriteArrayList 仅适用于写操作非常少的场景,而且能够容忍读写的短暂不一致。例如上面的例子中,写入的新元素并不能立刻被遍历到。另一个需要注意的是,CopyOnWriteArrayList 迭代器是只读的,不支持增删改。因为迭代器遍历的仅仅是一个快照,而对快照进行增删改是没有意义的。

(二)Map
Map 接口的两个实现是 ConcurrentHashMap 和 ConcurrentSkipListMap,它们从应用的角度来看,主要区别在于ConcurrentHashMap 的 key 是无序的,而 ConcurrentSkipListMap 的 key 是有序的。所以如果你需要保证 key 的顺序,就只能使用 ConcurrentSkipListMap。

使用 ConcurrentHashMap 和 ConcurrentSkipListMap 需要注意的地方是,它们的 key 和 value 都不能为空,否则会抛出NullPointerException这个运行时异常。下面这个表格总结了 Map 相关的实现类对于 key 和 value 的要求,你可以对比学习。

 ConcurrentSkipListMap 里面的 SkipList 本身就是一种数据结构,中文一般都翻译为“跳表”。跳表插入、删除、查询操作平均的时间复杂度是 O(log n),理论上和并发线程数没有关系,所以在并发度非常高的情况下,若你对 ConcurrentHashMap 的性能还不满意,可以尝试一下 ConcurrentSkipListMap。

(三)Set
Set 接口的两个实现是 CopyOnWriteArraySet 和 ConcurrentSkipListSet,使用场景可以参考前面讲述的 CopyOnWriteArrayList 和 ConcurrentSkipListMap,它们的原理都是一样的,这里就不再赘述了。

(四)Queue
Java 并发包里面 Queue 这类并发容器是最复杂的,你可以从以下两个维度来分类。一个维度是阻塞与非阻塞,所谓阻塞指的是当队列已满时,入队操作阻塞;当队列已空时,出队操作阻塞。另一个维度是单端与双端,单端指的是只能队尾入队,队首出队;而双端指的是队首队尾皆可入队出队。Java 并发包里阻塞队列都用 Blocking 关键字标识,单端队列使用 Queue 标识,双端队列使用 Deque 标识

这两个维度组合后,可以将 Queue 细分为四大类,分别是:

1.单端阻塞队列:其实现有 ArrayBlockingQueue、LinkedBlockingQueue、SynchronousQueue、LinkedTransferQueue、PriorityBlockingQueue 和 DelayQueue。内部一般会持有一个队列,这个队列可以是数组(其实现是 ArrayBlockingQueue)也可以是链表(其实现是 LinkedBlockingQueue);甚至还可以不持有队列(其实现是 SynchronousQueue),此时生产者线程的入队操作必须等待消费者线程的出队操作。而 LinkedTransferQueue 融合 LinkedBlockingQueue 和 SynchronousQueue 的功能,性能比 LinkedBlockingQueue 更好;PriorityBlockingQueue 支持按照优先级出队;DelayQueue 支持延时出队。

 2.双端阻塞队列:其实现是 LinkedBlockingDeque。

3.单端非阻塞队列:其实现是 ConcurrentLinkedQueue。
4.双端非阻塞队列:其实现是 ConcurrentLinkedDeque。

另外,使用队列时,需要格外注意队列是否支持有界(所谓有界指的是内部的队列是否有容量限制)。实际工作中,一般都不建议使用无界的队列,因为数据量大了之后很容易导致 OOM。上面我们提到的这些 Queue 中,只有 ArrayBlockingQueue 和 LinkedBlockingQueue 是支持有界的,所以在使用其他无界队列时,一定要充分考虑是否存在导致 OOM 的隐患。
 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/496743.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

12c oracle 激活_Windows运维之Windows server 2016 安装及ORACLE 12C 安装

本文主要向大家介绍了Windows运维之Windows server 2016 安装及ORACLE 12C 安装,通过具体的内容向大家展现,希望对大家学习Windows运维有所帮助。首先创建虚拟机,选择windows server 2016启动虚拟机,进入安装界面,语言…

工信部:筹建全国首个区块链和分布式记账标准化技术委员会

作者:李秀琴在3.15即将来临之时,我国工信部给区块链行业又带来了一大利好消息。3月12日,工业和信息化部(以下简称工信部)在官网发布公告称,其正在就筹建全国区块链和分布式记账技术标准化技术委员会事宜开展…

PowerDesigner11技巧

文章来源:http://blog.csdn.net/edeed/archive/2006/02/10/596271.aspx 1、安装PD v11.0版 2、由pdm生成建表脚本时,字段超过15字符就发生错误(oracle) 原因未知,解决办法是打开PDM后,会出现Database的菜单…

C++学习之路 | PTA乙级—— 1087 有多少不同的值 (20 分)(精简)

1087 有多少不同的值 (20 分) 当自然数 n 依次取 1、2、3、……、N 时,算式 ⌊n/2⌋⌊n/3⌋⌊n/5⌋ 有多少个不同的值?(注:⌊x⌋ 为取整函数,表示不超过 x 的最大自然数,即 x 的整数部分。) 输入…

Python 的 requests 库的用法

Python爬虫利器一之Requests库的用法:http://cuiqingcai.com/2556.html Python利用Requests库写爬虫(一):http://www.jianshu.com/p/e1f8b690b951 Python-第三方库requests详解:http://blog.csdn.net/shanzhizi/articl…

Java并发编程实战~Lock

再造管程的理由 synchronized导致死锁问题,提出了一个破坏不可抢占条件方案,但是这个方案 synchronized 没有办法解决。原因是 synchronized 申请资源的时候,如果申请不到,线程直接进入阻塞状态了,而线程进入阻塞状态…

wpf 点击按钮弹出选择框_WPF-PopupWindow wpf右下角弹出框,通过按钮调用,类似QQ CSharp C#编程 238万源代码下载- www.pudn.com...

文件名称: WPF-PopupWindow下载收藏√ [5 4 3 2 1 ]开发工具: C#文件大小: 90 KB上传时间: 2013-07-24下载次数: 19详细说明:wpf右下角弹出框,通过按钮调用,类似QQ弹出框-wpf lower right corner of the pop-up box文件列表(点击判断是否…

2018 年人工智能会怎么发展?这里有 8 个预测

来源:36氪普华永道发布了一份报告,对人工智能在2018年的发展趋势进行了研究,并做出了8项预测。人工智能非常复杂,而且发展速度很快。任何人都不可能对其未来几年的发展方向做出准确的预测。但就人工智能在2018年的发展趋势来说&am…

异常单据锁定涉及的数据库表

在软件使用过程中出现单据锁定提示,进入系统管理清除单据锁定,再进入软件还是提示单据锁定.(包括:审核凭证时提示单据锁定;不能录入期初余额,提示单据锁定;银行对帐单锁定 等情况) 造…

C 和 C++ 文件操作详解

来源:http://www.cnblogs.com/likebeta/archive/2012/06/16/2551662.html 来源:http://www.cnblogs.com/likebeta/archive/2012/06/16/2551780.html CPP 的文件操作 在C中,有一个stream这个类,所有的I/O都以这个“流”类为基础的…

redis 判断存在性_springboot + redis + 注解 + 拦截器 实现接口幂等性校验

提醒:后面有些图片模糊,请点击原文查看清晰图片一、概念幂等性, 通俗的说就是一个接口, 多次发起同一个请求, 必须保证操作只能执行一次比如:订单接口, 不能多次创建订单支付接口, 重复支付同一笔订单只能扣一次钱支付宝回调接口, 可能会多次回调, 必须处…

C++学习之路 | PTA乙级—— 1089 狼人杀-简单版(精简)

1089 狼人杀-简单版 (20 分)以下文字摘自《灵机一动好玩的数学》:“狼人杀”游戏分为狼人、好人两大阵营。在一局“狼人杀”游戏中,1 号玩家说:“2 号是狼人”,2 号玩家说:“3 号是好人”,3 号玩家说&#…

Java并发编程实战~Condition

利用两个条件变量快速实现阻塞队列呢&#xff1f; public class BlockedQueue<T>{final Lock lock new ReentrantLock();// 条件变量&#xff1a;队列不满 final Condition notFull lock.newCondition();// 条件变量&#xff1a;队列不空 final Condition notEmpty …

汽车行业最大创新仍未到来,四大力量将重塑未来汽车新纪元

来源&#xff1a; 资本实验室 作者&#xff1a;王进自第一辆福特“T”型车问世以来&#xff0c;汽车行业已经诞生了众多层出不穷、持续进化的创新成果。例如&#xff0c;制造商不断创造了新的车体风格&#xff0c;拓展了新的市场区隔&#xff0c;改进了自动换档和动力转向系…

C++学习之路 | PTA乙级——1090 危险品装箱 (25 分)(精简)

1090 危险品装箱 (25 分) 集装箱运输货物时&#xff0c;我们必须特别小心&#xff0c;不能把不相容的货物装在一只箱子里。比如氧化剂绝对不能跟易燃液体同箱&#xff0c;否则很容易造成爆炸。 本题给定一张不相容物品的清单&#xff0c;需要你检查每一张集装箱货品清单&#x…

echarts柱形图x轴y轴互换_数控机床在加工零件时,突然出现X、Y、Z轴失控?如何处理...

数控机床现在广泛应用于单品种大批量的零件加工中&#xff0c;由于稳定性强、精度高、效率高&#xff0c;取代了原来的普通机床。同时数控铣床、数控车床被大规模的配置到各产品自动化生产线上&#xff0c;实现了自动化无入管理。但在生产中由于数控机床的伺服系统出现故障&…

PHP新手上路(十)

9. 简易banner动态更替   不知大家有没有发现各大站点上的标头广告banner&#xff0c;我们每次访问这些站点时&#xff0c;都会看到不同的广告图标&#xff0c;或者如果你每次刷新页面时&#xff0c;这些广告banner就会不断地随机更替变换。要实现这种效果虽然用javascript…

python beautiful soup库的用法

Python 爬虫利器二 之 Beautiful Soup 的用法&#xff1a;http://cuiqingcai.com/1319.html Beautiful Soup 4.2.0 文档&#xff1a;https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html Python3 --- BeautifulSoup --- 节点选择器&#xff1a;https://www.…

Java并发编程实战~原子类

对于简单的原子性问题&#xff0c;还有一种无锁方案&#xff0c;先看看如何利用原子类解决累加器问题。 public class Test {AtomicLong count new AtomicLong(0);public void add10K() {int idx 0;while(idx < 10000) {count.getAndIncrement();}}} 无锁方案相对互斥锁…

著名物理学家斯蒂芬•霍金去世,他曾告诫人类要学会避免人工智能可能的风险

据多家媒体报道&#xff0c;著名的英国物理学家斯蒂芬霍金于3 月 14 日去世&#xff0c;享年 76 岁。霍金教授的孩子露西&#xff0c;罗伯特和蒂姆发表了声明确认了这一消息。斯蒂芬威廉霍金(Stephen William Hawking)&#xff0c;1942年1月8日出生于英国牛津&#xff0c;英国剑…