java 并发 set_高并发下的Java数据结构(List、Set、Map、Queue)

1.并发List

Vector 或者 CopyOnWriteArrayList 是两个线程安全的List实现,ArrayList 不是线程安全的。因此,应该尽量避免在多线程环境中使用ArrayList。如果因为某些原因必须使用的,则需要使用Collections.synchronizedList(List list)进行包装。

示例代码:

List list = Collections.synchronizedList(new ArrayList());

...

synchronized (list) {

Iterator i = list.iterator(); // 必须在同步块中

while (i.hasNext())

foo(i.next());

}

遍历的操作需要自己加锁,而add之类的方法则不需要,自己看一下源码就理解了

CopyOnWriteArrayList 的内部实现与Vector又有所不同。顾名思义,Copy-On-Write 就是 CopyOnWriteArrayList 的实现机制。即当对象进行写操作时,复制该对象;若进行的读操作,则直接返回结果,操作过程中不需要进行同步。

CopyOnWriteArrayList 很好地利用了对象的不变性,在没有对对象进行写操作前,由于对象未发生改变,因此不需要加锁。而在试图改变对象时,总是先获取对象的一个副本,然后对副本进行修改,最后将副本写回。

这种实现方式的核心思想是减少锁竞争,从而提高在高并发时的读取性能,但是它却在一定程度上牺牲了写的性能。

在 get() 操作上,Vector 使用了同步关键字,所有的 get() 操作都必须先取得对象锁才能进行。在高并发的情况下,大量的锁竞争会拖累系统性能。反观CopyOnWriteArrayList 的get() 实现,并没有任何的锁操作。

在 add() 操作上,CopyOnWriteArrayList 的写操作性能不如Vector,原因也在于Copy-On-Write。

在读多写少的高并发环境中,使用 CopyOnWriteArrayList 可以提高系统的性能,但是,在写多读少的场合,CopyOnWriteArrayList  的性能可能不如 Vector。

Copy-On-Write源码分析

通过查看CopyOnWriteArrayList类的源码可知,在add操作上,是使用了Lock锁做了同步处理,内部拷贝了原数组,并在新数组上进行添加操作,最后将新数组替换掉旧数组。

public boolean add(E e) {

final ReentrantLock lock = this.lock;

lock.lock();

try {

Object[] elements = getArray();

int len = elements.length;

Object[] newElements = Arrays.copyOf(elements, len + 1);

newElements[len] = e;

setArray(newElements);

return true;

} finally {

lock.unlock();

}

}

CopyOnWriteArrayList的get(int index)方法是没有任何锁处理的,直接返回数组对象。

public E get(int index) {

return get(getArray(), index);

}

final Object[] getArray() {

return array;

}

那么Copy-On-Write的优缺点有哪些呢?

最明显的就是这是CopyOnWriteArrayList属于线程安全的,并发的读是没有异常的,读写操作被分离。缺点就是在写入时不止加锁,还使用了Arrays.copyOf()进行了数组复制,性能开销较大,遇到大对象也会导致内存占用较大。

2.并发Set

和List相似,并发Set也有一个 CopyOnWriteArraySet ,它实现了 Set 接口,并且是线程安全的。它的内部实现完全依赖于 CopyOnWriteArrayList ,因此,它的特性和 CopyOnWriteArrayList 完全一致,适用于 读多写少的高并发场合,在需要并发写的场合,则可以使用Set s = Collections.synchronizedSet(Set s)得到一个线程安全的Set。

示例代码:

Set s = Collections.synchronizedSet(new HashSet());

...

synchronized (s) {

Iterator i = s.iterator(); // 必须在同步块中

while (i.hasNext())

foo(i.next());

}

3.并发Map

在多线程环境下使用Map,一般也可以使用Collections.synchronizedMap()方法得到一个线程安全的 Map(详见示例代码1)。但是在高并发的情况下,这个Map的性能表现不是最优的。由于 Map 是使用相当频繁的一个数据结构,因此 JDK 中便提供了一个专用于高并发的 Map 实现 ConcurrentHashMap。

Collections的示例代码1:

Map m = Collections.synchronizedMap(new HashMap());

...

Set s = m.keySet();  // 不需要同步块

...

synchronized (m) {  // 同步在m上,而不是s上!!

Iterator i = s.iterator(); // 必须在同步块中

while (i.hasNext())

foo(i.next());

}

1.为什么不能在高并发下使用HashMap?

因为多线程环境下,使用Hashmap进行put操作会引起死循环,导致CPU利用率接近100%,所以在并发情况下不能使用HashMap。

2.为什么不使用线程安全的HashTable?

HashTable容器使用synchronized来保证线程安全,但在线程竞争激烈的情况下HashTable的效率非常低下。因为当一个线程访问HashTable的同步方法时,其他线程访问HashTable的同步方法时,可能会进入阻塞或轮询状态。如线程1使用put进行添加元素,线程2不但不能使用put方法添加元素,并且也不能使用get方法来获取元素,所以竞争越激烈效率越低。

3.ConcurrentHashMap的优势

ConcurrentHashMap的内部实现进行了锁分离(或锁分段),所以它的锁粒度小于同步的 HashMap;同时,ConcurrentHashMap的 get() 操作也是无锁的。除非读到的值是空的才会加锁重读,我们知道HashTable容器的get方法是需要加锁的,那么ConcurrentHashMap的get操作是如何做到不加锁的呢?原因是它的get方法里将要使用的共享变量都定义成volatile。

锁分离:首先将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。有些方法需要跨段,比如size()和containsValue(),它们可能需要锁定整个表而而不仅仅是某个段,这需要按顺序锁定所有段,操作完毕后,又按顺序释放所有段的锁。

上述部分文字参考文章:https://www.cnblogs.com/ITtangtang/p/3948786.html

4.并发Queue

在并发队列上,JDK提供了两套实现,一个是以 ConcurrentLinkedQueue 为代表的高性能队列,一个是以 BlockingQueue 接口为代表的阻塞队列。不论哪种实现,都继承自 Queue 接口。

ConcurrentLinkedQueue 是一个适用于高并发场景下的队列。它通过无锁的方式,实现了高并发状态下的高性能。通常,ConcurrentLinkedQueue 的性能要好于 BlockingQueue 。

与 ConcurrentLinkedQueue 的使用场景不同,BlockingQueue 的主要功能并不是在于提升高并发时的队列性能,而在于简化多线程间的数据共享。

BlockingQueue 典型的使用场景是生产者-消费者模式,生产者总是将产品放入 BlockingQueue 队列,而消费者从队列中取出产品消费,从而实现数据共享。

BlockingQueue 提供一种读写阻塞等待的机制,即如果消费者速度较快,则 BlockingQueue 则可能被清空,此时消费线程再试图从 BlockingQueue 读取数据时就会被阻塞。反之,如果生产线程较快,则 BlockingQueue 可能会被装满,此时,生产线程再试图向 BlockingQueue 队列装入数据时,便会被阻塞等待,其工作模式如图所示。

b198f321a9a495aa2ea3e72980f0c5eb.png

5.并发Deque

在JDK1.6中,还提供了一种双端队列(Double-Ended Queue),简称Deque。Deque允许在队列的头部或尾部进行出队和入队操作。与Queue相比,具有更加复杂的功能。

Deque 接口的实现类:LinkedList、ArrayDeque和LinkedBlockingDeque。

它们都实现了双端队列Deque接口。其中LinkedList使用链表实现了双端队列,ArrayDeque使用数组实现双端队列。通常情况下,由于ArrayDeque基于数组实现,拥有高效的随机访问性能,因此ArrayDeque具有更好的遍性能。但是当队列的大小发生变化较大时,ArrayDeque需要重新分配内存,并进行数组复制,在这种环境下,基于链表的 LinkedList 没有内存调整和数组复制的负担,性能表现会比较好。但无论是LinkedList或是ArrayDeque,它们都不是线程安全的。

LinkedBlockingDeque 是一个线程安全的双端队列实现。可以说,它已经是最为复杂的一个队列实现。在内部实现中,LinkedBlockingDeque 使用链表结构。每一个队列节点都维护了一个前驱节点和一个后驱节点。LinkedBlockingDeque 没有进行读写锁的分离,因此同一时间只能有一个线程对其进行操作。因此,在高并发应用中,它的性能表现要远远低于 LinkedBlockingQueue,更要低于 ConcurrentLinkedQueue 。

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

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

相关文章

知识图谱和图分析与可视化

来源:知链数据“知识图谱和图分析与可视化”这个题目看起来比较大,我尝试基于本人的一些图数据可视化与分析经验,对知识图谱和图分析与可视化之间的关系进行简单梳理,并分享一些以知识图谱为代表的图数据与图可视化、图分析结合进…

新一代人工智能专利分析

来源:三思派人工智能(Artificial Intelligence,AI)自诞生以来,已经过约60年的发展。2006年深度学习算法的重大突破带来了人工智能的第三次爆发。同时也引发专利申请的激增,2006年至2016年,十年的…

MYSQL性能优化详解(二)

接着上一篇学习:http://www.cnblogs.com/quanzhiguo/p/6401453.html 七、MySQL数据库Schema设计的性能优化 高效的模型设计 适度冗余-让Query尽两减少Join 大字段垂直分拆-summary表优化 大表水平分拆-基于类型的分拆优化 统计表-准实时优化 合适的数据类型 时间存储…

图解谷歌大脑丶城市大脑丶全球脑与互联网大脑的关系

人类很早就朦胧的发现社会组织具有神经系统的特征。19世纪到20世纪,一些前瞻的哲学家们开始不断将科技与脑进行了关联,提出了"器官映射","社会神经网络","全球脑"。 21世纪之后,更多科技大脑概念不断涌现,从互联网大脑到城市大脑,从谷…

滴滴自动驾驶CEO张博:十年内无人驾驶对消费者没有吸引力丨厚势汽车

来源:WAVE2019张博:在 2012 年滴滴创立的时候,我们是一个非常简单的想法。我们发现在打出租车的场景下,无论是司机还是乘客效率都非常低。在滴滴出现之前,一个乘客想要打出租车必须要下楼招一下手,这个信号…

garch预测 python_数据科学方面的Python库,实用!

作者:Python开发与大数据人工智能原文:公众号 Python开发与大数据人工智能Python是一种很棒的编程语言。事实上,它还是世界上发展最快的编程语言之一。它一次又一次证明了它在数据科学职位中的实用性。整个Python及其库的生态系统使其成为全世…

物联网中的推荐系统

来源:北京物联网智能技术应用协会作者 | Alexander Felfernig, Seda Polat Erdeniz编译 | CDA数据科学研究院Recommender systems in the Internet of Things1、背景介绍物联网是一种联网的基础架构,是物联网、互联网和语义学领域之间融合的结果&#xf…

pwm控制的基本原理_单片机PWM控制基本原理详解~

PWM是Pulse Width Modulation的缩写,它的中文名字是脉冲宽度调制,一种说法是它利用微处理器的数字输出来对模拟电路进行控制的一种有效的技术,其实就是使用数字信号达到一个模拟信号的效果。这是个什么概念呢?我们一步步来介绍。首…

关上Deepfake的潘多拉魔盒,RealAI推出深度伪造视频检测工具

诞生之初,Deepfake是一项有趣的图像处理技术,仅仅带来搞笑和娱乐视频,但殊不知,潘多拉魔盒就此被打开,催生出色情黑产、恶搞政客“操纵”民意,Deepfake正逐步进化为一种新型“病毒”,人类伦理道…

谷歌地图的全球森林监察系统,揭秘中国雾霾的惊天秘密!

来源:老牛时评谷歌公司最近推出的全新交互式地图——“全球森林监察”它可以实时显示全球森林的覆盖情况。该幅地图的数据来源有多个,其中包括了NASA的森林面积覆盖率的分析数据。于是我们选取了中国及中国周边的部分,看完后的感受只能是比悲…

qt显示rgba8888 如何改 frame_Qt开源作品17-IP地址输入控件

一、前言这个IP地址输入框控件,估计写烂了,网上随便一搜索,保证一大堆,估计也是因为这个控件太容易了,非常适合新手练手,一般的思路都是用4个qlineedit控件拼起来,然后每个输入框设置正则表达式…

web.xml文件头出错

原先将web.xml文件头设置为如下格式 <?xml version"1.0" encoding"UTF-8"?><web-app version"3.1" xmlns"http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance" xsi:sche…

Nature子刊超越诺贝尔经典理论:神经科学研究路漫漫...

科学家正在观察一台用于记录小鼠脑细胞活动的双光子显微镜。图片来源&#xff1a;艾伦研究所来源&#xff1a;中国生物技术网 北京时间12月17日&#xff0c;发表在《Nature Neuroscience》上一项针对小鼠视觉系统中近6万个神经元活动的新研究显示&#xff0c;要想了解大脑如何计…

偏见与人类大脑结构有关

来源&#xff1a;科技日报偏见是如何产生的&#xff1f;据英国《自然神经科学》16日发表的一项脑科学研究发现&#xff0c;内侧前额叶皮质后部&#xff08;pMFC&#xff09;会促进人类产生确认偏误。具体而言&#xff0c;对于那些不会让自己更加相信已有观念的意见&#xff0c;…

PLECS软件学习使用(一)简单的RLC电路搭建

PLECS软件学习使用&#xff08;一&#xff09;简单的RLC电路搭建 1相关操作总结&#xff1a; 旋转&#xff1a;CtrlR 翻转&#xff1a;CtrlF 从连线中引出线&#xff1a;Ctrl鼠标左键 设置元件参数&#xff1a;双击元件&#xff0c;进行设置&#xff0c;若要显示参数&#xff0…

《自然》公布年度十大杰出论文

来源&#xff1a;科技日报 英国《自然》杂志网站日前公布了2019年十大杰出论文&#xff0c;接近室温的超导体、精确编辑基因技术、海王星新卫星等纷纷入选。其中&#xff0c;中国研究占到两席&#xff0c;分别是来自复旦大学的亨廷顿舞蹈症新疗法&#xff0c;与中科院上海有机化…

中国电子信息工程科技发展十大趋势(2019)发布

来源&#xff1a;新浪科技17日&#xff0c;中国工程院信息与电子学部、中国信息与电子工程科技发展战略研究中心在中国工程院召开发布会&#xff0c;发布“中国电子信息工程科技发展十大趋势&#xff08;2019&#xff09;”。中国工程院副院长陈左宁院士表示&#xff0c;中国工…

Android junit单元测试

1.首先要把下面配置好&#xff08;注释的地方 Android studio 无需配置&#xff09;&#xff0c;targetPackage项目的包名 2.创建Android项目会自动生成test包&#xff0c;只能在test包下使用junit测试 3.在方法的前面加上Test就可以使用junit了 4.解释一下&#xff1a; assert…

21世纪20年代改变世界的十大趋势

来源&#xff1a;美国银行美国银行发布了新报告“21世纪20年代改变世界的十大趋势”。全球化高峰&#xff1a;世界范围内劳力、货物和资本自由流动将终结。在这种趋势下&#xff0c;赢家是本地市场和实物资产&#xff0c;而输家则是全球市场。衰退&#xff1a;更多的FMS投资者认…

多个if用什么设计模式_抽丝剥茧——单例设计模式

单例设计模式兄弟们好&#xff0c;今天是最后一个设计模式了&#xff0c;也是我们最熟悉的单例设计模式&#xff0c;可以说这个设计模式是我们最先接触到的设计模式了。想当年学习JavaSE的时候&#xff0c;老师聊到一个「饿汉式和懒汉式」&#xff0c;我还纠结了半天&#xff0…