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

目录

一、多线程环境使用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.mzph.cn/news/715447.shtml

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

相关文章

蓝桥杯Python B组练习——python复习2

蓝桥杯Python B组练习——python复习2 一、简介 复习python,参考书《Python编程从入门到实践》,[美]Eric Mathes著。前一部分见专栏——蓝桥杯Python B组练习 这一部分不全,不想写了 二、字典 1.一个简单的字典 来看一个游戏&#xff0…

模拟服务器响应的测试框架:moco

第1章:引言 大家好,我是小黑,在这篇博客中,咱们要聊聊Moco测试框架。这个框架,可不是一般的小伙伴,它在模拟服务器响应这块儿,可是有不少看家本领。 首先,Moco是啥呢?简…

stable diffusion webUI之赛博菩萨【秋葉】——工具包新手安裝与使用教程

stable diffusion webUI之赛博菩萨【秋葉】——工具包新手安裝与使用教程 AI浪潮袭来,还是学习学习为妙赛博菩萨【秋葉】简介——(葉ye,四声,同叶)A绘世启动器.exe(sd-webui-aki-v4.6.x)工具包安…

住房贷款利息退税笔记

应该缴税了才能退税,如果是学生,没有缴税应该是无法退税的。 产权证明 如果是商品房,没有取得房产证,那就是房屋预售合同 扣除年度 应选择上一年 扣除比例 没有结婚,选否 申报方式

unity 数学 如何计算线和平面的交点

已知一个平面上的一点P0和法向量n,一条直线上的点L0和方向L,求该直线与该平面的交点P 如下图 首先我们要知道向量归一化点乘之后得到就是两个向量的夹角的余弦值,如果两个向量相互垂直则值是0,小于0则两个向量的夹角大于90度,大于…

(C语言)函数详解上

(C语言)函数详解上 目录: 1. 函数的概念 2. 库函数 2.1 标准库和头文件 2.2 库函数的使用方法 2.2.1 sqrt 功能 2.2.2 头文件包含 2.2.3 实践 2.2.4 库函数文档的一般格式 3. 自定义函数 3.1 函数的语法形式 3.2 函数的举例 4. 形参和实参 4.…

MySQL-CDC 新增同步表确无法捕获增量问题处理

Flink-CDC版本&#xff1a;2.3.0 问题描述 之前通过Flink-CDC捕获Mysql数据库的数据变更情况&#xff0c;代码大致如下&#xff1a; StreamExecutionEnvironment env StreamExecutionEnvironment.getExecutionEnvironment(flinkEnvConf);MySqlSource<String> mysql …

Redis--事务机制的详解及应用

Redis事务的概念&#xff1a; Redis事务就是将一系列命令包装成一个队列&#xff0c;在执行时候按照添加的顺序依次执行&#xff0c;中间不会被打断或者干扰&#xff0c;在执行事务中&#xff0c;其他客户端提交的命令不可以插入到执行事务的队列中&#xff0c;简单来说Redis事…

【Linux】进程优先级以及Linux内核进程调度队列的简要介绍

进程优先级 基本概念查看系统进程修改进程的优先级Linux2.6内核进程调度队列的简要介绍和进程优先级有关的概念进程切换 基本概念 为什么会存在进程优先级&#xff1f;   进程优先级用于确定在资源竞争的情况下&#xff0c;哪个进程将被操作系统调度为下一个运行的进程。进程…

SSH教程

ssh 是远程连接的利器, 可以说凡是涉及到 linux 服务器, ssh 就是一个绕不开的话题. 本文作为一个教程, 尽可能详细的帮助读者设置 ssh, 并给出一些常用的 ssh 配置方法 (主要用于 linux 系统的远程登录和文件传输). 1. 简介 ssh 分为两个部分, sshd 服务端和 ssh 客户端. ssh…

黑马鸿蒙学习笔记1:TEXT组件

业余时间学习下黑马鸿蒙课程&#xff0c;主要截取重要的PPT学习&#xff1a; 其实就是用$r&#xff08;&#xff09;的方法&#xff0c;去调用本地化资源文件&#xff0c;可以做多语言了。 比如每个语言目录下都有个string.json文件&#xff0c;然后用键值对name,value的方式搭…

JVM 补充——StringTable

具体哪些String是相等的&#xff0c;各种String的情况&#xff0c;看这个&#xff1a; https://javaguide.cn/java/basis/java-basic-questions-02.html#string-%E4%B8%BA%E4%BB%80%E4%B9%88%E6%98%AF%E4%B8%8D%E5%8F%AF%E5%8F%98%E7%9A%84 String的基本特性 String&#xf…

【C++】STL简介 | STL六大组件 | string类 | string类对象操作

目录 1. 什么是STL 2. STL的版本 3. STL的六大组件 4. STL的缺陷 5. 引出string类 6. 标准库中的string类 6.1 string类简介 6.2 string类对象的构造 6.3. string类对象的容量 6.4. string类对象的遍历 6.5. string类对象的修改 6.6. string类非成员函数 6.7. vs…

基于CNN-LSTM-Attention的时间序列回归预测matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1卷积神经网络&#xff08;CNN&#xff09;在时间序列中的应用 4.2 长短时记忆网络&#xff08;LSTM&#xff09;处理序列依赖关系 4.3 注意力机制&#xff08;Attention&#xff09; 5…

MySQL 学习记录 2

原文&#xff1a;https://blog.iyatt.com/?p13818 13 存储引擎 查看一下前面创建的一张表的创建语句&#xff0c;当时并没有显式指定引擎&#xff0c;MySQL 自动指定的 InnoDB&#xff0c;即默认引擎是这个。 创建表的时候要显式指定引擎可以参考这个语句 查看当前 MySQL …

JWT基于Cookie的会话保持,并解决CSRF问题的方案

使用JWT进行浏览器接口请求&#xff0c;在使用Cookie进行会话保持传递Token时&#xff0c;可能会存在 CSRF 漏洞问题&#xff0c;同时也要避免在产生XSS漏洞时泄漏Token问题&#xff0c;如下图在尽可能避免CSRF和保护Token方面设计了方案。 要点解释如下&#xff1a; 将JWT存入…

Snagit 2024:让你的屏幕活动瞬间变得生动有力 mac/win版

Snagit 2024 屏幕录制与截图软件是一款功能强大的工具&#xff0c;专为现代用户设计&#xff0c;以满足他们在工作、学习和娱乐中对屏幕内容捕捉和分享的需求。这款软件结合了屏幕录制和截图功能&#xff0c;为用户提供了一种高效、便捷的方式来捕捉屏幕上的精彩瞬间。 Snagit…

xxl-job--01--简介

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 1.xxl-job1. 1 发展历史1.2 XXL-JOB的系统架构1.3 xxl-job与其他框架对比 2. XXL-JOB的使用2.1 准备工作- 配置调度中心XXL-JOB的数据表 2.2 配置执行器1 引入依赖包…

vue cesium加载点与定位到指定位置

vue cesium定位到指定位置 window.viewer.camera.flyTo({destination: Cesium.Cartesian3.fromDegrees(point.longDeg, point.latDeg, 6500000), orientation: {heading: 6.2079384332084935, roll: 0.00031509431759868534, pitch: -1.535}, duration: 3})vue cesium加载点 …

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

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