集合类的线程安全问题

news2024/9/23 13:31:12

集合类

原来的集合类,大部分都不是线程安全的
Vector, Stack, HashTable, 是线程安全的(不建议用), 其他的集合类不是线程安全的.
加了锁,不一定就是线程安全的,不加锁也不一定是线程不安全的,需要具体问题具体分析
虽然get,set方法都加了synchronized,但是如果不能正确使用,也可能会出现线程安全问题
1.如果是多个线程,并发执行set操作,由于synchronized限制,是线程安全.
2.如果多个线程进行一些复杂的操作,比如先判定get的值是xxxx,再进行set,就出现了一种情况,使得整个逻辑变得不是一个原子级别的任务
即使把这里的get和set分别进行加锁,如果不能正确的使用,也可能产生线程安全问题,而且在单线程的情况下,有可能会因为synchronized影响到执行效率

多线程环境使用 ArrayList

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

Collections.synchronizedList(new ArrayList);
ArrayList本身没有使用synchronized,但是你又不想自己加锁,就可以使用上面这个方法.,相当于让ArrayList像Vector一样工作

使用 CopyOnWriteArrayList

CopyOnWrite容器即写时复制的容器。
当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,
复制出一个新的容器,然后新的容器里添加元素,
添加完元素之后,再将原容器的引用指向新的容器。
这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。
所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。
优点:
在读多写少的场景下, 性能很高, 不需要加锁竞争.
缺点:

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

多线程环境使用队列

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

多线程环境使用哈希表

HashMap 本身不是线程安全的.
在多线程环境下使用哈希表可以使用:
Hashtable
ConcurrentHashMap

Hashtable

只是简单的把关键方法加上了 synchronized 关键字.
这相当于直接针对 Hashtable 对象本身(this)加锁.
如果多线程访问同一个 Hashtable 就会直接造成锁冲突(读也会).
size 属性也是通过 synchronized 来控制同步, 也是比较慢的.
一旦触发扩容, 就由该线程完成整个扩容过程. 这个过程会涉及到大量的元素拷贝, 效率会非常低.

ConcurrentHashMap

相比于 Hashtable 做出了一系列的改进和优化. 以 Java1.8 为例
读操作没有加锁(但是使用了 volatile 保证从内存读取结果), 只对写操作进行加锁. 加锁的方式仍然是是用 synchronized, 但是不是锁整个对象, 而是 “锁桶” (用每个链表的头结点作为锁对象), 大大降低了锁冲突的概率.
充分利用 CAS 特性. 比如 size 属性通过 CAS 来更新. 避免出现重量级锁的情况.
优化了扩容方式: 化整为零
发现需要扩容的线程, 只需要创建一个新的数组, 同时只搬几个元素过去.
扩容期间, 新老数组同时存在.
后续每个来操作 ConcurrentHashMap 的线程, 都会参与搬家的过程. 每个操作负责搬运一小部分元素.
搬完最后一个元素再把老数组删掉.
这个期间, 插入只往新数组加.
这个期间, 查找需要同时查新数组和老数组
在这里插入图片描述
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.coloradmin.cn/o/936106.html

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

相关文章

RabbitMQ从原理到实战—基于Golang【万字详解】

文章目录 前言一、MQ是什么?优势劣势 二、MQ的用途1、应用解耦2、异步加速3、削峰填谷4、消息分发 三、RabbitMQ是什么1、AMQP 协议2、RabbitMQ 包含的要素3、RabbitMQ 基础架构 四、实战1、Simple模式(即最简单的收发模式)2、Work Queues 模型3、Publish/Subscribe…

ESP8266固件烧录

文章目录 硬件电路烧录工具完整固件资料+烧录工具硬件电路 烧写模式: GPIO0:0 此时通过REST复位引脚复位,8266进入烧写模式。 烧写通过串口烧写,波特率设置115200 运行模式: GPIO0:1 此时通过REST复位引脚复位,8266进入烧写模式。 烧录工具 烧写工具下载链接:https:…

Python功能制作之简单的绘画板

可能需要安装的库 pip install pillow pip install tk制作 我们使用Python的Tkinter库创建的一个简单绘画软件。 首先创建了一个简单的绘画应用,可以选择颜色、切换画笔和橡皮擦模式、清空画布以及绘制自由曲线。 里面的主要结构和功能是: 导入必要的…

计算机组成原理(主存储器的基本组成、 运算器的基本组成、 控制器的基本组成、完成一条指令的三个阶段)

主存储器的基本组成: 这个是读数据操作图: 读入数据与菜鸟驿站的取货流程差不多: 写入数据的过程与读入数据类似: 1、cpu 指明想要写入到那个位置(写到MAR中) 2、想要写入的数据会放到MDR中 3、c…

ctfshow-web-红包题第七弹

0x00 前言 CTF 加解密合集CTF Web合集 0x01 题目 0x02 Write Up 首先上来访问就是phpinfo。常规思路先扫一下目录。 发现一个.git文件403,这种情况通常都是存在文件夹,但是不能直接访问文件夹导致的。那么我们可以使用git_extract工具进行获取内容。…

WSL2连接不了外网怎么办?

某天忽然WLAN变成地球图标,上不了Internet,搞了半天网络适配器,仍然不行。回忆之前做过的操作,曾经运行过ZoogVPN,试着启动并连接,然后退出,WLAN神奇地恢复了连接,可以上Internet了。…

leetcode题解 滑动窗口总结

一、解题思路 滑动窗口使用思路(寻找最长) ——核心:左右双指针(left,right)在起始点,right向右逐位滑动循环 ——每次滑动过程中 如果:窗口内满足条件,right向右扩大…

Yolo系列-yolov3

YOLO-V3 这张图讲道理真的过分了!!!我不是针对谁,在座的各位都是 终于到V3了,最大的改进就是网络结构,使其更适合小目标检测特征做的更细致,融入多持续特征图信息来预测不同规格物体 先验框更丰…

【springboot】Spring Cache缓存:

文章目录 一、导入Maven依赖&#xff1a;二、实现思路&#xff1a;三、代码开发&#xff1a; 一、导入Maven依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-cache</artifactId><…

基于单片机的智能数字电子秤proteus仿真设计

一、系统方案 1、当电子称开机时&#xff0c;单片机会进入一系列初始化&#xff0c;进入1602显示模式设定&#xff0c;如开关显示、光标有无设置、光标闪烁设置&#xff0c;定时器初始化&#xff0c;进入定时器模式&#xff0c;如初始值赋值。之后液晶会显示Welcome To Use Ele…

开源项目的版本管理:Git的最佳实践

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

【C语言】操作符大全(保姆级介绍)

&#x1f6a9;纸上得来终觉浅&#xff0c; 绝知此事要躬行。 &#x1f31f;主页&#xff1a;June-Frost &#x1f680;专栏&#xff1a;C语言 &#x1f525;该篇将详细介绍各种操作符的功能。 目录&#xff1a; &#x1f4d8; 前言① 算术操作符②移位操作符③位操作符④赋值操…

Linux服务——nginx的配置及模块

目录 一、nignx配置 1、nginx的配置文件 2、使用server语句块构建虚拟主机 3、alias别名 4、location语句 二、nginx模块 access模块 验证模块 自定义错误页面 日志存放位置 检测文件是否存在 长连接设置 ngx_http_autoindex_module 模块 三、nginx的高级配置 1、…

深入理解Reactor模型的原理与应用

1、什么是Reactor模型 Reactor意思是“反应堆”&#xff0c;是一种事件驱动机制。 和普通函数调用的不同之处在于&#xff1a;应用程序不是主动的调用某个 API 完成处理&#xff0c;而是恰恰相反&#xff0c;Reactor逆置了事件处理流程&#xff0c;应用程序需要提供相应的接口并…

Illustrator打开visio导出的emf为什么会报错

问题描述 将使用Visio绘制的.emf文件直接拖入Adobe Illustrator有时候会弹出如下报错窗口——“无法完成操作&#xff0c;因为出现未知错误。” 原因分析 经过多次测试&#xff0c;发现这个跟Visio中元素的数量有关&#xff0c;当数量>24或>27&#xff08;差不多就这…

Git向远程仓库与推送以及拉取远程仓库

理解分布式版本控制系统 1.中央服务器 我们⽬前所说的所有内容&#xff08;⼯作区&#xff0c;暂存区&#xff0c;版本库等等&#xff09;&#xff0c;都是在本地也就是在你的笔记本或者计算机上。⽽我们的 Git 其实是分布式版本控制系统&#xff01;什么意思呢? 那我们多人…

如何评价国产CEC-IDE开发工具

前两天&#xff0c;看到了一则信息&#xff1a;新出的“自主研发”的 CEC-IDE&#xff0c;于是在好奇心的驱使下打开了官网。 主页&#xff1a;https://cecide.digitalgd.com.cn/monorepo/app-front/home 文档&#xff1a;https://cecide.digitalgd.com.cn/monorepo/app-fron…

深入探讨C存储类和存储期——Storage Duration

&#x1f517; 《C语言趣味教程》&#x1f448; 猛戳订阅&#xff01;&#xff01;&#xff01; ​—— 热门专栏《维生素C语言》的重制版 —— &#x1f4ad; 写在前面&#xff1a;这是一套 C 语言趣味教学专栏&#xff0c;目前正在火热连载中&#xff0c;欢迎猛戳订阅&#…

软件设计师学习笔记7-输入输出技术+总线+可靠性+性能指标

目录 1.输入输出技术 1.1数据传输控制方式 1.2中断处理过程 2.总线 3.可靠性 3.1可靠性指标 3.2串联系统与并联系统 3.3混合模型 4.性能指标 1.输入输出技术 即CPU控制主存与外设交互的过程 1.1数据传输控制方式 (1)程序控制&#xff08;查询&#xff09;方式&…