当前位置: 首页 > article >正文

多线程进阶-线程安全的集合类

目录

🥇多线程环境使⽤ ArrayList

🥈多线程环境使⽤队列

🥉多线程环境使⽤哈希表

🏆相关面试题


原来的集合类,大部分都不是线程安全的
Vector,Stack,HashTable,是线程安全的(不建议用),其他的集合类不是线程安全的

🥇多线程环境使⽤ ArrayList

1. ⾃⼰使⽤同步机制 (synchronized 或者 ReentrantLock),自己加锁

2. Collections.synchronizedList(new ArrayList);

synchronizedList 是标准库提供的⼀个基于 synchronized 进⾏线程同步的 List. synchronizedList 的关键操作上都带有 synchronized

3. 使⽤ CopyOnWriteArrayList
CopyOnWrite容器即写时复制的容器。
🥛当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Coy,复制
出一个新的容器,然后新的容器里添加元素,
🥛添加完元素之后,再将原容器的引用指向新的容器。

这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添
加任何元素。
所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。
优点:
在读多写少的场景下,性能很高,不需要加锁竞争
缺点:
1.占用内存较多
2.新写的数据不能被第一时间读取到.

🥈多线程环境使⽤队列

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

🥉多线程环境使⽤哈希表

HashMap本身不是线程安全的.
在多线程环境下使用哈希表可以使用:
●Hashtable(不推荐)
●ConcurrentHashMap(Java方向top5 超高频面试题)🎯🎯🎯

此处的这个数据结构,相比于HashMap和Hashtable来说,改进力度非常的

☃️优化了锁的粒度[最核心]

读操作没有加锁(但是使用了volatile保证从内存读取结果),只对写操作进行加锁.加锁的方式仍然是用synchronized,但是不是锁整个对象,而是"锁桶"(用每个链表的头结点作为锁对象),大大降低了锁冲突的概率

❄️充分利⽤ CAS 特性. ⽐如 size 属性通过 CAS 来更新. 避免出现重量级锁的情况.

🌊针对读操作,做了特殊处理。上述的加锁,只是针对写操作,加锁。对于读操作的话,通过volatile以及一些精巧的代码实现,确保读操作,不会读到"修改一半的数据"。

💦优化了扩容⽅式: 化整为零
普通hash表扩容,需要创建新的hash表,把元素都搬运过去。这一系列操作,很有可能就在一次put就完成了,就会使这次put开销非常大,耗时非常长.

🌏发现需要扩容的线程,只需要创建一个新的数组,同时只搬几个元素过去.
🌏扩容期间,新老数组同时存在.
🌏后续每个来操作ConcurrentHashMap的线程,都会参与搬家的过程.每个操作负责搬运一小部分元素
🌏搬完最后一个元素再把老数组删掉.
🌏这个期间,插入只往新数组加。
🌏这个期间,查找需要同时查新数组和老数组

🏆相关面试题

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

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

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

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

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

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

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

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

4️⃣Hashtable和HashMap、ConcurrentHashMap 之间的区别?

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

Hashtable: 线程安全. 使⽤ synchronized 锁 Hashtable 对象, 效率较低. key 不允许为 null.

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


http://www.kler.cn/a/508094.html

相关文章:

  • 联通用户管理系统(一)
  • 交直流混合微电网多台互联变换器并联
  • 如何在vue中渲染markdown内容?
  • Mysql--实战篇--大数据量表的分页优化(自增长主键,子查询主键主查询全部,查询条件加索引,覆盖索引等)
  • 学习threejs,使用OrbitControls相机控制器
  • 《鸿蒙Next微内核:解锁人工智能决策树并行计算的加速密码》
  • 游戏如何检测Xposed框架
  • C#实例化类,当类名和方法一样或者不一样时运行流程
  • 【达梦数据库(Oracle模式)】如何将视图中的数据导出
  • Python 爬虫学习指南与资料分享
  • rsync结合inotify实现文件实时同步
  • Lua项目下SSRF利用Redis文件覆盖lua回显RCE
  • 人工智能之深度学习_[3] -PyTorch自动微分模块和构建线性回归模型
  • 1.1初探大模型:起源与发展
  • 如何将数据库字符集改为中文,让今后所有的数据库都支持中文
  • 二十三种设计模式-代理模式
  • IF=24.5! 综述:机器人纹理识别触觉感知和机器学习进展
  • 请求响应-
  • 【算法】差分
  • python爬取Boss直聘,分析北京招聘市场
  • Android-V lmkd 中的那些属性值
  • WORD转PDF脚本文件
  • 如何攻击一个服务器(仅用于教育及娱乐实验目的)
  • 从零用java实现 小红书 springboot vue uniapp (10)系统消息模块 接收推送消息优化
  • 浅谈计算机网络04 | 现代网络需求与技术支撑
  • C++内存分布