多线程(进阶四:线程安全的集合类)

news2024/9/23 12:35:55

目录

一、多线程环境使用ArrayList

二、多线程环境使用队列

三、多线程环境使用哈希表

1、HashMap

2、Hashtable

3、ConcurrentHashMap

(1)缩小了锁的粒度

(2)充分使用了CAS原子操作,减少一些加锁

(3)针对扩容操作的一些优化(化整为零)

四、相关面试题


大部分集合类都是线程不安全的,Vector,Stack,Hashtable是线程安全的,但不建议使用,因为无论什么情况都要加锁,甚至单线程也是,这样就很不合理;并且这几个集合类官方已经不推荐使用了,可能在未来的版本中就被删掉了。

下面介绍一些线程不安全的集合类。

一、多线程环境使用ArrayList

1、自己使用同步机制(synchronized或者ReentrantLock)

2、Collections.synchronizedList(new ArrayList);

        相当于给ArrayList套了个壳,ArrayList各种操作本身是不带锁的,通过上述操作套壳后,得到了新的对象,新的对象里面的关键方法都是带有锁的。

3、使用CopyOnWriteArrayList

        CopyOnWrite容器即写时复制的容器,多线程对这个顺序表进行读操作时,不会有线程安全问题,但是当多线程进行写操作时,就会有线程安全问题,CopyOnWriteArrayList会复制一份原来的顺序表,并且修改新的顺序表内容,再把原来的引用指向新的顺序表(此操作是原子的,不需要加锁)。


二、多线程环境使用队列

1、自己加锁

2、使用BlockingQueue

1. ArrayBlockingQueue
基于数组实现的阻塞队列
2. LinkedBlockingQueue
基于链表实现的阻塞队列
3. PriorityBlockingQueue
基于堆实现的带优先级的阻塞队列
4. TransferQueue
最多只包含⼀个元素的阻塞队列


三、多线程环境使用哈希表

1、HashMap

        HashMap本身就是线程不安全的。

2、Hashtable

        在一些关键方法上加了锁

        这也相当于对this加了锁,也就是针对Hashtable对象本身加锁,如果尝试修改Hash表中两个不同Hash值里的链表,会发生锁冲突。如图:

3、ConcurrentHashMap

相对于Hashtable,进行了些优化。

(1)缩小了锁的粒度

        多线程如果修改Hash表里Hash值不同的链表都发生锁冲突,是不合理的,而且锁冲突是很耗时的,所以ConcurrentHashMap是对Hash表里每个链表都进行加锁,这样,不同的链表有不同的锁对象,多线程修改两个不同的链表,就不会发生锁冲突了,如图:

注意:更多的锁并不意味着要耗费更多的空间,因为在java中的任何对象都可以作为锁对象,而本身Hash表中就得有数组,数组元素都已经存在,即链表的头结点,每个链表都有一个头结点,可以直接把这个头结点作为链表的锁对象。

(2)充分使用了CAS原子操作,减少一些加锁

        比如,针对Hash表元素个数的维护。

(3)针对扩容操作的一些优化(化整为零)

        负载因子:描述了每个桶(Hash表)平均有多少个元素;公式:实际个数 / 数组长度(桶的个数)。0.75是默认的扩容阈值(也可以是其他数字值),如果我们算出的负载因子超过规定的扩容阈值,Hash表就会进行扩容。

        进行扩容时,如果不是concurrentHashMap,会创建一个更大是数组,把旧的数组元素搬运到新的数组中,一次性的全部搬运完,如果Hash表本身的元素就非常多,这里扩容就会非常耗时,但可能过一会儿就又好了,存在不稳定因素,我们无法控制Hash表何时触发扩容。

        concurrentHashMap则不是一次性的全部搬运完,而是把Hash表中的元素分为若干次搬运完,而不是直接一次性梭哈完,假设Hash表有1kw个元素,每次就只搬运5k哥元素,一共花费2k次搬运完成(搬运的时间会更长一些),但能确保每次搬运消耗的时间不会很长,避免出现很卡的情况。

总的来说,扩容是一个低频的操作(前提把扩容阈值设置合理),运行整个程序,可能一天都不会触发扩容,触发了每次可能会花费几分钟的时间进行搬运。

注意:在扩容过程中,存在两份Hash表,一份是新的,一份是旧的。

        进行插入操作,直接往新的Hash表上插入。

        进行删除操作,新的旧的都要删除。

        进行查找操作,新的旧的都要查找。


四、相关面试题

1.ConcurrentHashMap的读是否要加锁,为什么?

 读操作没有加锁.目的是为了进一步降低锁冲突的概率.为了保证读到刚修改的数据,搭配了volatile关键字.

2.介绍下ConcurrentHashMap的锁分段技术?

这个是Java1.7所采取的技术.Java1.8中已经不再使用了.简单的说就是把若干个哈希桶分成一个"段"(Segment),针对每个段分别加锁.

目的也是为了降低锁冲突的概率.当两个线程访问的数据恰好在同一个段上时,才会触发锁竞争

3.ConcurrentHashMap在jdk1.8做了哪些优化?

取消了分段锁,直接给每个哈希桶(每个链表)分配了一个锁(就是以每个链表的头节点对象作为锁对象).

将原来的数组 + 链表的实现方式改进成 数组 + 链表 /红黑树的方式.当链表较长的时候(大于等于8个元素)就转换成红黑树. 

4.HashMap和HashTable,ConcurrentHashMap之间的区别?

HashMap: 线程不安全.key允许为null

HashTable:线程安全.使用synchronized锁HashTable对象,效率较低.key不允许设置为null.

ConcurrentHashMap: 线程安全.使用synchronized锁每个链表的头节点,锁冲突概率较低,充分利用CAS机制,优化了扩容方式.key不允许为null. 


都看到这了,点个赞再走吧,谢谢谢谢谢

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

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

相关文章

优选算法|【双指针】283.移动零

题目 283. 移动零 给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。 请注意 ,必须在不复制数组的情况下原地对数组进行操作。 示例 1: 输入: nums [0,1,0,3,12]输出: [1,3,12,0,0]示例 2: 输入…

基于ssm旅社客房收费管理系统+vue

目 录 目 录 I 摘 要 III ABSTRACT IV 1 绪论 1 1.1 课题背景 1 1.2 研究现状 1 1.3 研究内容 2 2 系统开发环境 3 2.1 vue技术 3 2.2 JAVA技术 3 2.3 MYSQL数据库 3 2.4 B/S结构 4 2.5 SSM框架技术 4 3 系统分析 5 3.1 可行性分析 5 3.1.1 技术可行性 5 3.1.2 操作可行性 5 3…

PTA L2-005 集合相似度

给定两个整数集合,它们的相似度定义为:Nc​/Nt​100%。其中Nc​是两个集合都有的不相等整数的个数,Nt​是两个集合一共有的不相等整数的个数。你的任务就是计算任意一对给定集合的相似度。 输入格式: 输入第一行给出一个正整数N…

IEEE 802.1Qbv标准解析:为实时应用提供可靠网络基础设施

IEEE 802.1Qbv是IEEE 802.1家族中的一项重要标准,专门针对实时流量的时间敏感性进行优化。这一标准在网络通信领域,特别是在对实时性要求极高的应用中,如音视频传输、工业自动化、智能交通系统等,具有极其重要的地位。 在传统的以…

递推算法(c++)

递推可以说是递归反过来的一种算法,递归是从后往前倒着算,递推是从前往后正着算。 统计每个月兔子的总数 题目描述 有一对兔子,从出生后第3个月起每个月都生一对兔子,一对小兔子长到第三个月后每个月又生一对兔子, …

为什么HashMap的键值可以为null,而ConcurrentHashMap不行?

写在开头 今天在写《HashMap很美好,但线程不安全怎么办?ConcurrentHashMap告诉你答案!》这篇文章的时候,漏了一个知识点,知道晚上吃饭的时候才凸显想到,关于ConcurrentHashMap在存储Key与Value的时候&…

ARM架构基础内容

文章目录 前言一、AAPCS二、中断调用过程三、FreeRTOS中任务切换的实质总结 前言 一、AAPCS AAPCS,全称为ARM Architecture Procedure Call Standard,是ARM架构下的过程调用标准。这个标准定义了在ARM架构中函数调用和返回的约定,以确保不同…

文件底层的深入理解(1)

一、文件学习的简单铺垫 我们都知道,文件等于文件内容加上文件属性。访问文件之前都得先通过进程才能打开相应的文件,一个进程可以打开多个文件。修改文件,都是通过执行代码的方式完成修改。要对文件进行修改(或其他操作&#xff…

Java 数组(详细)

目录 一、数组的概述 1. 数组的理解: 2. 数组相关的概念: 3. 数组的特点: 4. 数组的分类: 5.数据结构: 二、一维数组 1. 一维数组的声明与初始化 2. 一维数组元素的引用: 3. 数组的属性&#xff1…

微信小程序,h5端自适应登陆方式

微信小程序端只显示登陆(获取opid),h5端显示通过账户密码登陆 例如: 通过下面的变量控制: const isWeixin ref(false); // #ifdef MP-WEIXIN isWeixin.value true; // #endif

力扣hot100题解(python版44-47题)

44、二叉搜索树中第K小的元素 给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 个最小元素(从 1 开始计数)。 示例 1: 输入:root [3,1,4,null,2], k 1 输出:…

FHE 的应用场景

参考文献: [MSM22] Marcolla C, Sucasas V, Manzano M, et al. Survey on fully homomorphic encryption, theory, and applications[J]. Proceedings of the IEEE, 2022, 110(10): 1572-1609. 文章目录 FHEFirst GenerationSecond GenerationThird GenerationFour…

编码规则转换

思考: 如何将一个机内码转换为区内码? 只要将机内码减去 A0A0 就可以啦 如果只让我们用加法器来解决呢? 注意我们的数据占用了 32 位,如果想用补码进行减法运算的话,符号位怎么办??&#xf…

2199. 骑士共存问题(最小割,最大权独立集,二分图)

活动 - AcWing 在一个 n∗n 个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示。 棋盘上某些方格设置了障碍,骑士不得进入。 对于给定的 n∗n个方格的国际象棋棋盘和障碍标志,计算棋盘上最多可以放置多少个…

2024年腾讯云优惠券_代金券_云服务器折扣券免费领取链接

腾讯云优惠代金券领取入口共三个渠道,腾讯云新用户和老用户均可领取8888元代金券,可用于云服务器等产品购买、续费和升级使用,阿腾云atengyun.com整理腾讯云优惠券(代金券)领取入口、代金券查询、优惠券兑换码使用方法…

UE5中实现后处理深度描边

后处理深度描边可以通过取得边缘深度变化大的区域进行描边,一方面可以用来做角色的等距内描边,避免了菲尼尔边缘光不整齐的问题,另一方面可以结合场景扫描等特效使用,达到更丰富的效果: 后来解决了开启TAA十字线和锯齿…

【go从入门到精通】go包,内置类型和初始化顺序

大家好,这是我给大家准备的新的一期专栏,专门讲golang,从入门到精通各种框架和中间件,工具类库,希望对go有兴趣的同学可以订阅此专栏。 go基础 。 Go文件名: 所有的go源码都是以 ".go" 结尾&…

latex宏包pythontex使用简明手册

文章目录 1.背景2. 基本示例2.1 hello world2.1.1 代码与输出结果2.1.2 说明2.1.3 如何编译使用了pythontex宏包的Latex文档2.1.4 如何既输出python代码又输出代码执行结果 2.2 在Latex中嵌入python变量的值2.2.1 示例代码与文档输出2.2.2 说明 2.3 在latex文档中输出控制台会话…

2.29号的复盘开始商城项目的规格如何设施的方式

第五次设计方式 我本来想的是,按照对于的组方式解拆分,通过分组处理的内存不同查询对应的手机上 出现问就是这里 对于的组相应规格相应里面有对于的价格,价格也就相同,无法进行区分 查询出来的对应的结果 还是没有办法具体拆分…

现货大宗商品发售平台搭建须知

在搭建现货大宗商品发售平台时,需要考虑以下关键因素: 目标市场分析:首先要明确你的平台将服务于哪些大宗商品市场,如农产品、金属、能源等。了解这些市场的特点、参与者、交易规则等,有助于你设计出更符合市场需求的…