【Java EE】线程安全的集合类

news2024/11/16 2:44:09

目录

  • 🌴多线程环境使用 ArrayList
  • 🎍多线程环境使⽤队列
  • 🍀多线程环境使⽤哈希表
    • 🌸 Hashtable
    • 🌸ConcurrentHashMap
  • ⭕相关面试题
  • 🔥其他常⻅问题

原来的集合类, 大部分都不是线程安全的.

Vector, Stack, HashTable, 是线程安全的(不建议⽤), 其他的集合类不是线程安全的.

那如何在多线程环境下安全的使用 集合类呢?

🌴多线程环境使用 ArrayList

1. ⾃⼰使⽤同步机制 (synchronized 或者 ReentrantLock)
前⾯做过很多相关的讨论了. 此处不再展开.可以查看博主之前的博客
2. Collections.synchronizedList(new ArrayList);

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

3. 使⽤ CopyOnWriteArrayList

CopyOnWrite容器即写时复制的容器。
• 当我们往⼀个容器添加元素的时候,不直接往当前容器添加,⽽是先将当前容器进⾏Copy,复制
出⼀个新的容器,然后新的容器⾥添加元素,
• 添加完元素之后,再将原容器的引⽤指向新的容器。

这样做的好处是我们可以对CopyOnWrite容器进⾏并发的读,⽽不需要加锁,因为当前容器不会添
加任何元素

所以CopyOnWrite容器也是⼀种读写分离的思想,读和写不同的容器。
优点:
在读多写少的场景下, 性能很⾼, 不需要加锁竞争.
缺点:

  1. 占⽤内存较多.
  2. 新写的数据不能被第⼀时间读取到

🎍多线程环境使⽤队列

  1. ArrayBlockingQueue

基于数组实现的阻塞队列

  1. LinkedBlockingQueue

基于链表实现的阻塞队列

  1. PriorityBlockingQueue

基于堆实现的带优先级的阻塞队列

  1. TransferQueue

最多只包含⼀个元素的阻塞队列

🍀多线程环境使⽤哈希表

HashMap 本⾝不是线程安全的.

在多线程环境下使⽤哈希表可以使⽤:
Hashtable
ConcurrentHashMap

🌸 Hashtable

只是简单的把关键⽅法加上了 synchronized 关键字
在这里插入图片描述

相当于直接针对 Hashtable 对象本⾝加锁.
• 如果多线程访问同⼀个 Hashtable 就会直接造成锁冲突.
• size 属性也是通过 synchronized 来控制同步, 也是⽐较慢的.
• ⼀旦触发扩容, 就由该线程完成整个扩容过程. 这个过程会涉及到⼤量的元素拷⻉, 效率会⾮常低.

在这里插入图片描述

🌸ConcurrentHashMap

相⽐于 Hashtable 做出了⼀系列的改进和优化. 以 Java1.8 为例

  1. 读操作没有加锁(但是使⽤了 volatile 保证从内存读取结果), 只对写操作进⾏加锁. 加锁的⽅式仍然是⽤ synchronized, 但是不是锁整个对象, ⽽是 "锁桶" (⽤每个链表的头结点作为锁对象), ⼤⼤降低了锁冲突的概率.
  2. 充分利⽤ CAS 特性. ⽐如 size 属性通过 CAS 来更新. 避免出现重量级锁的情况.
  3. 优化了扩容⽅式: 化整为零
  • 发现需要扩容的线程, 只需要创建⼀个新的数组, 同时只搬⼏个元素过去.
  • 扩容期间, 新⽼数组同时存在.
  • 后续每个来操作 ConcurrentHashMap 的线程, 都会参与搬家的过程. 每个操作负责搬运⼀⼩部
    分元素.
  • 搬完最后⼀个元素再把⽼数组删掉.
  • 这个期间, 插⼊只往新数组加.
  • 这个期间, 查找需要同时查新数组和⽼数组
    在这里插入图片描述
    ConcurrentHashMap每个哈希桶都有一把锁,只有两个线程访问的恰好是同一个哈希桶上的数据才会出现锁冲突。

⭕相关面试题

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

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

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

这个是 Java1.7 中采取的技术. Java1.8 中已经不再使⽤了. 简单的说就是把若⼲个哈希桶分成⼀个
“段” (Segment), 针对每个段分别加锁.
⽬的也是为了降低锁竞争的概率. 当两个线程访问的数据恰好在同⼀个段上的时候, 才触发锁竞争.

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

取消了分段锁, 直接给每个哈希桶(每个链表)分配了⼀个锁(就是以每个链表的头结点对象作为锁对
象).
将原来 数组 + 链表 的实现⽅式改进成 数组 + 链表 / 红⿊树 的⽅式. 当链表较⻓的时候(⼤于等于 8 个
元素)就转换成红⿊树.

  1. Hashtable和HashMap、ConcurrentHashMap 之间的区别?

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

🔥其他常⻅问题

  1. 谈谈 volatile关键字的⽤法?

volatile 能够保证内存可⻅性. 强制从主内存中读取数据. 此时如果有其他线程修改被 volatile 修饰的
变量, 可以第⼀时间读取到最新的值

  1. Java多线程是如何实现数据共享的?

JVM 把内存分成了这⼏个区域:
⽅法区, 堆区, 栈区, 程序计数器.
其中堆区这个内存区域是多个线程之间共享的.
只要把某个数据放到堆内存中, 就可以让多个线程都能访问到.

  1. Java创建线程池的接⼝是什么?参数 LinkedBlockingQueue 的作⽤是什么?

创建线程池主要有两种⽅式:
• 通过 Executors ⼯⼚类创建. 创建⽅式⽐较简单, 但是定制能⼒有限.
• 通过 ThreadPoolExecutor 创建. 创建⽅式⽐较复杂, 但是定制能⼒强.
LinkedBlockingQueue 表⽰线程池的任务队列. ⽤⼾通过 submit / execute 向这个任务队列中
添加任务, 再由线程池中的⼯作线程来执⾏任务.

  1. Java线程共有⼏种状态?状态之间怎么切换的?

• NEW: 安排了⼯作, 还未开始⾏动. 新创建的线程, 还没有调⽤ start ⽅法时处在这个状态.
• RUNNABLE: 可⼯作的. ⼜可以分成正在⼯作中和即将开始⼯作. 调⽤ start ⽅法之后, 并正在 CPU 上
运⾏/在即将准备运⾏ 的状态.
• BLOCKED: 使⽤ synchronized 的时候, 如果锁被其他线程占⽤, 就会阻塞等待, 从⽽进⼊该状态.
• WAITING: 调⽤ wait ⽅法会进⼊该状态.
• TIMED_WAITING: 调⽤ sleep ⽅法或者 wait(超时时间) 会进⼊该状态.
• TERMINATED: ⼯作完成了. 当线程 run ⽅法执⾏完毕后, 会处于这个状态

  1. 在多线程下,如果对⼀个数进⾏叠加,该怎么做?

• 使⽤ synchronized / ReentrantLock 加锁
• 使⽤ AtomInteger 原⼦操作.

  1. Servlet是否是线程安全的?

Servlet 本⾝是⼯作在多线程环境下.
如果在 Servlet 中创建了某个成员变量, 此时如果有多个请求到达服务器, 服务器就会多线程进⾏操
作, 是可能出现线程不安全的情况的

  1. Thread和Runnable的区别和联系?

Thread 类描述了⼀个线程.
Runnable 描述了⼀个任务.
在创建线程的时候需要指定线程完成的任务, 可以直接重写 Thread 的 run ⽅法, 也可以使⽤
Runnable 来描述这个任务.

  1. 多次start⼀个线程会怎么样

第⼀次调⽤ start 可以成功调⽤.
后续再调⽤ start 会抛出 java.lang.IllegalThreadStateException 异常

  1. 有synchronized两个⽅法,两个线程分别同时⽤这个⽅法,请问会发⽣什么?

synchronized 加在⾮静态⽅法上, 相当于针对当前对象加锁.
如果这两个⽅法属于同⼀个实例:
线程1 能够获取到锁, 并执⾏⽅法. 线程2 会阻塞等待, 直到线程1 执⾏完毕, 释放锁, 线程2 获取到锁之
后才能执⾏⽅法内容.
如果这两个⽅法属于不同实例:
两者能并发执⾏, 互不⼲扰.

  1. 进程和线程的区别?

• 进程是包含线程的. 每个进程⾄少有⼀个线程存在,即主线程。
• 进程和进程之间不共享内存空间. 同⼀个进程的线程之间共享同⼀个内存空间.
• 进程是系统分配资源的最⼩单位,线程是系统调度的最⼩单位。

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

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

相关文章

EndNote 21:文献整理与引用,一键轻松搞定 mac/win版

EndNote 21是一款功能强大的文献管理软件,专为学术研究者、学生和教师设计。它提供了全面的文献管理解决方案,帮助用户轻松整理、引用和分享学术文献。 EndNote 21软件获取 EndNote 21拥有直观的用户界面和强大的文献检索功能,用户可以轻松地…

昇腾ACL应用开发之硬件编解码dvpp

1.前言 在我们进行实际的应用开发时,都会随着对一款产品或者AI芯片的了解加深,大家都会想到有什么可以加速预处理啊或者后处理的手段?常见的不同厂家对于应用开发的时候,都会提供一个硬件解码和硬件编码的能力,这也是抛…

【C++干货基地】揭秘C++11常用特性:内联函数 | 范围for | auto自动识别 | nullptr指针空值

🎬 鸽芷咕:个人主页 🔥 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想,就是为了理想的生活! 引入 哈喽各位铁汁们好啊,我是博主鸽芷咕《C干货基地》是由我的襄阳家乡零食基地有感而发,不知道各位的…

基于springboot实现校园爱心捐赠互助管理系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现校园爱心捐赠互助管理系统演示 摘要 随着互联网及电子商务平台的飞速发展,利用在线平台实现的二手商品交易以及在线捐赠已经非常普遍,很多高校目前还存在贫困生需要通过爱心人士的捐助来完成学业,同时很多高校的大学生也希…

【C++】STL学习之旅——初识STL,认识string类

string类 1 STL 简介2 STL怎么学习3 STL缺陷4 string4.1 初识 string4.2 初步使用构造函数成员函数 5 小试牛刀Thanks♪(・ω・)ノ谢谢阅读!!!下一篇文章见!!! 1 STL 简介 …

PyCharm如何添加python库

1.使用pip命令在国内源下载需要的库 下面使用清华源,在cmd中输入如下命令就可以了 pip install i https://pypi.tuna.tsinghua.edu.cn/simple 包名版本号2.如果出现报错信息,Cannot unpack file…这种情况,比如下面这种 ERROR: Cannot unpa…

考研复试指南

1. 记住,复试的本质不是考试,而是一场自我展示。 考研复试并非简单的知识考察,更是一场展示自我能力和潜力的机会。除了学科知识,考官更关注你的综合素质、学术兴趣和未来发展规划。因此,要保持自信,用更全…

前端canvas项目实战——简历制作网站(五):右侧属性栏(字体、字号、行间距)

目录 前言一、效果展示二、实现步骤1. 优化代码,提取常量2. 实现3个编辑模块3. 实现updateFontProperty方法4. 一个常见的用法:仅更新当前选中文字的样式 三、Show u the code后记 前言 上一篇博文中,我们扩充了线条对象(fabric.…

带你快速初步了解Python字典

1.字典 定义多个数据一般使用列表,但是列表也存在一定的缺陷 若列表中有多个元素,想访问其中某个元素,比较不方便 定义字典的语法:{key1:value1, key2:value2, key3:value3......} 字典和列表习惯的使用场景: &qu…

(3)(3.1) FlightDeck FrSky发射器应用程序

文章目录 前言 1 概述 2 Turnkey Packages 3 参数说明 前言 ​Craft and Theory 的 FlightDeck 可让你轻松查看飞行模式、高度、速度、姿态和关键系统警报,包括故障保护和电池错误,如电池不平衡警告和发射机低电量警报。 1 概述 Craft and Theory 的…

Jmeter 安装

JMeter是Java的框架,因此在安装Jmeter前需要先安装JDK,此处安装以Windows版为例 1. 安装jdk:Java Downloads | Oracle 安装完成后设置环境变量 将环境变量JAVA_HOME设置为 C:\Program Files\Java\jdk1.7.0_25 在系统变量Path中添加 C:\Pro…

【NR 定位】3GPP NR Positioning 5G定位标准解读(一)

目录 前言 1. 3GPP规划下的5G技术演进 2. 5G NR定位技术的发展 2.1 Rel-16首次对基于5G的定位技术进行标准化 2.2 Rel-17进一步提升5G定位技术的性能 3. Rel-18 关于5G定位技术的新方向、新进展 3.1 Sidelink高精度定位功能 3.2 针对上述不同用例,3GPP考虑按…

JAVAEE初阶 JVM(二)

垃圾回收和双亲委派模型 1.双亲委派模型2.垃圾回收机制(1) 识别垃圾1.引用计数2.可达性分析 (2) 销毁垃圾1.标记清除2.复制算法3.标记整理 3.分代回收 1.双亲委派模型 描述了如何查找.class文件的策略. 同时JVM中有专门进行类加载的操作,有一个模块,叫做类加载器. 上述就是为了…

安装Realtek Audio Driver失败[Error Code:-0001]

安装Realtek Audio Driver失败[Error Code:-0001] 首先来看一下我们遇到的问题GPT4的推荐解决方法(流水账)笔者自己真实有效的解决办法 首先来看一下我们遇到的问题 描述:在笔记本更新完电脑之后,没有自带声音驱动。然…

实例:NX二次开发收集关于Open C的计时信息

目录 一、概述 二、实现的功能 三、代码实现以及详细解析 一、概述 在NX二次开发过程中,我们为了效率经常会进行Open C的计时统计,这个实例可用于收集关于Open C的计时信息程序,并且在计时测试中很有用。该实例通过UF_begin_timer启动一个…

Pyglet图形界面版2048游戏——详尽实现教程(上)

目录 Pyglet图形界面版2048游戏 一、色块展示 二、绘制标题 三、方阵色块 四、界面布局 五、键鼠操作 Pyglet图形界面版2048游戏 一、色块展示 准备好游戏数字的背景颜色,如以下12种: COLOR ((206, 194, 180, 255), (237, 229, 218, 255), (23…

首例以“冠状病毒”为主题的勒索病毒,篡改系统MBR

前言概述 2020年勒索病毒攻击仍然是网络安全的最大威胁,在短短三个月的时间里,已经出现了多款新型的勒索病毒,关于2020年勒索病毒攻击新趋势,可以阅读笔者写的上一篇文章,里面有详细的分析,从目前观察到的…

深入解剖指针(4)

个人主页(找往期文章包括但不限于本期文章中不懂的知识点): 我要学编程(ಥ_ಥ)-CSDN博客 目录 回调函数 qsort使用举例 使用qsort函数排序整型数据 使用qsort排序结构数据 qsort函数的模拟实现 回调函数 回调函数就是一个通过函数指…

java-幂等性

幂等性 1.1幂等性定义: 在计算机领域中,幂等(Idempotence)是指任意一个操作的多次执行总是能获得相同的结果,不会对系统状态产生额外影响。在Java后端开发中,幂等性的实现通常通过确保方法或服务调用的结…

68-解构赋值,迭代器,生成器函数,Symbol

1.解构赋值(针对数组array&#xff0c;字符串String及对象object以) 结构赋值是一种特殊的语法&#xff0c;通过将各种结构中的元素复制到变量中达到"解构"的目的&#xff0c;但是数组本身没有改变 1.1解构单层数组 <script>let arr [1,2,3,4,5];//获取数组…