【JavaEE】线程安全的集合类

作者主页:paper jie_博客

本文作者:大家好,我是paper jie,感谢你阅读本文,欢迎一建三连哦。

本文于《JavaEE》专栏,本专栏是针对于大学生,编程小白精心打造的。笔者用重金(时间和精力)打造,将基础知识一网打尽,希望可以帮到读者们哦。

其他专栏:《MySQL》《C语言》《javaSE》《数据结构》等

内容分享:本期将会分享线程安全的集合类芝士

目录

引入

多线程使用ArrayList

多线程使用队列

多线程使用哈希表

Hashtable

ConcurrentHashMap

相关面试题


引入

之前我们所学的集合类,大多数都是线程不安全的.,像ArrayList,LinkedList,Queue等都是线程不安全的.这里我们将介绍`线程安全的类

多线程使用ArrayList

1.可以自己使用synchronized来加锁实现线程安全

2.Collections.synchronizedList(new ArrayList);

它就相当于给ArrayList套了一个壳,通过这个壳得到了一个新的对象,这个新的对象的关键方法就加上了synchronized.

3.使用CopyOnWritArrayList

当我们放容器中添加元素时,不会往旧容器中添加,而是会将当前这个容器的数据拷贝到一个新的容器中.添加完元素后,在将原有容器的引用指向新的容器.

它带来的好处就是我们可以对CopyWritArrayList容器进行并发的读,不需要加锁,因为当前容器不会添加任何元素.

优点就是在读多写少的场景下,性能很高,不需要加锁.

缺点就是比较占用内存,新写的数据不能第一时间读到.且不适用与写多的场景.

多线程使用队列

1.ArrayListBlockingQueue

2.LinkedListBlockingQue

3.priorityBlockingQueue

4.TransferQueue

只包含一个元素的阻塞队列.

多线程使用哈希表

Hashtable

在数据结构中,我们学过hashmap和hashset,这两者本身其实是线程不安全的.在所线程的环境下我们就可以使用Hashable和CouncurrentHashMap.

而我们的Hashtable就是在关键方法中加上了synchronized关键字,这其实就是直接对Hashtable对象本身直接加锁.这就会出现一些问题:

如果多个线程访问同一个Hashtable就会造成锁冲突.

size属性也是被synchronized控制,这样锁冲突会进一步加大.

一但触发扩容,就会由该线程来完成扩容过程,这个过程机会涉及到大量的元素拷贝,这里的速度就会很慢.

一个Hashtable就只有一个锁,只要有两个线程访问这个HashTable中的任意一个数据就会发生锁竞争.这里读操作和其他链表的元素是不会发生线程安全问题的,但是这里还是会有锁.

ConcurrentHashMap

相比于Hashtable,ConcurrentHashMap就做出了一系列的改进和优化.这里以Java1.8为例:

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

2. 充分的利用了CAS特性.size属性就是使用CAS来更新的,这样就又降低了锁冲突的概率.

3. 优化了扩容方法,采用的是化整为零.

发现需要扩容的线程,只需要创建出一个数组,再搬运少量元素过去即可.

扩容期间,新老数组同时存在

后面每个操作ConcurrentMap的线程都会参与搬运数组的任务,每个操作都会搬运一小部分

直到搬运完最后一个元素再将老数组删除.

这个期间插入元素只往新数组中插入.

这个期间查找删除元素新数组和老数组都需要查找和删除.

相关面试题

  1. ConcurrentHashMap的读是否要加锁?

读不需要加锁,这样可以减少锁冲突.但是为了及时读到刚修改的数据,搭配了volatile关键字.

  1. 介绍ConcurrentHashMap的分段技术?

这是Java1.7中采用的技术.Java1.8中已经不再使用了.它就是将若干个链表分成一个段,给段加上锁,目的还是为了降低锁竞争的概率.当两个线程访问的数据在一个段中就会发生锁竞争.

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

取消了分段锁,直接给每个哈希桶每个链表分配了一个锁.将原来数组+链表的实现方式改变为数组+链表+红黑树的方式.当链表大于等于8时就会由链表转变为红黑树.

4.Hashtable和HashMap,ConcurrentHashMap的区别?

HashMap: 线程不安全,key可以为null

Hashtable: 线程安全,使用synchronized锁加在Hashtable对象上,效率低.且key不可以为null

ConcurrentHashMap: 线程安全,使用synchronized锁加在每个链表上,锁冲突率低,充分利用CAS机制,优化了扩容方式,key不能为null.

相关推荐
一线大码1 分钟前
项目中怎么确定线程池的大小
java·后端
要加油哦~4 分钟前
vue · 插槽 | $slots:访问所有命名插槽内容 | 插槽的使用:子组件和父组件如何书写?
java·前端·javascript
crud7 分钟前
Spring Boot 3 整合 Swagger:打造现代化 API 文档系统(附完整代码 + 高级配置 + 最佳实践)
java·spring boot·swagger
天天摸鱼的java工程师12 分钟前
从被测试小姐姐追着怼到运维小哥点赞:我在项目管理系统的 MySQL 优化实战
java·后端·mysql
vortex519 分钟前
探索 Shell:选择适合你的命令行利器 bash, zsh, fish, dash, sh...
linux·开发语言·bash·shell·dash
zzc92121 分钟前
MATLAB仿真生成无线通信网络拓扑推理数据集
开发语言·网络·数据库·人工智能·python·深度学习·matlab
周某某~24 分钟前
四.抽象工厂模式
java·设计模式·抽象工厂模式
HUN金克斯30 分钟前
C++/C函数
c语言·开发语言·c++
慢半拍iii31 分钟前
数据结构——F/图
c语言·开发语言·数据结构·c++
钢铁男儿33 分钟前
C# 表达式和运算符(表达式和字面量)
开发语言·c#