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

news2024/11/14 14:45:41

文章目录

  • 线程安全的集合类
    • 多线程环境使用ArrayList
    • 多线程环境使用队列
    • 多线程环境使用哈希表
      • Hashtable
      • ConcurrentHashMap


线程安全的集合类

之前学习的集合类大部分都不是线程安全的.
比如ArrayList,Queue,HashMap等等,这都是线程不安全的.

Vector,Stack,Hashtable,这些集合类虽然是线程安全的(内置了synchronized),但是实际上这几个东西并不推荐使用,因为它们都是无脑加锁的.

多线程环境使用ArrayList

  1. 自己加锁

  2. 使用标准库中提供的带锁的List,Collections.synchronizedList(new ArrayList);
    synchronizedList就相当于构造出了一个核心方法,自带synchronized的List.
    在这里插入图片描述

  3. 使用CopyOnWriteArrayList
    这个集合类,没有加锁,但是通过"写实拷贝"来实现的线程安全.通过写时拷贝,避免两个线程同时修改一个变量.
    在这里插入图片描述

    写实拷贝介绍:当我们往一个容器添加元素的时候,不直接往当前容器内添加,而是先将当前容器Copy,复制出一个新的容器,然后在新的容器里添加元素.添加完元素之后,再将原容器的引用指向新的容器.

    在这里插入图片描述

    • 在拷贝过程中,读操作,都仍然读取旧版本的内容.写操作,则是在新版本的内容上修改.
    • 这个修改引用指向的操作,本身是原子的,即使在这个过程中,存在大量的读操作,读取内容.此时,仍然能够确保读到的数据是有效的(读到的数据要么是旧版本的数据,要么是新版本数据,不会是一个"修改了一半"的数据)

    写实拷贝的缺点:

    1. 无法应对多个线程同时修改的情况
    2. 如果涉及到的数据量很大,拷贝起来就非常慢.(占用内存较多)
    3. 新写入的数据不能被第一时间读取到.

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

多线程环境使用队列

  1. ArrayBlockingQueue: 基于数组实现的阻塞队列
    在这里插入图片描述

  2. LinkedBlockingQueue: 基于链表实现的阻塞队列
    在这里插入图片描述

  3. PriorityBlockingQueue: 基于堆实现的带优先级的阻塞队列
    在这里插入图片描述

  4. TransferQueue: 最多只包含一个元素的阻塞队列
    在这里插入图片描述

多线程环境使用哈希表

Hashtable

Hashtable只是简单的把关键方法加上了synchronized关键字.
在这里插入图片描述
在这里插入图片描述
这相当于直接针对Hashtable对象本身加锁.

这样做有几个缺点:

  1. 如果多线程访问同一个Hashtable就会直接造成锁冲突.
  2. size属性也是通过synchronized来控制同步,也是比较慢的.
  3. 一旦触发扩容,就由该线程完成整个扩容过程,这个过程会涉及到大量的元素拷贝,效率会非常低.

ConcurrentHashMap

Hashtable虽然是可选项,但是我们更推荐使用ConcurrentHashMap.
ConcurrentHashMap相比于HashMap和Hashtable来说,它的改进力度非常大.

这个部分的内容非常重要,可以认为是整个Java方向,高频面试题,能排到top5的问题.

  1. ConcurrentHashMap优化了锁的粒度[最核心]
    Hashtable的加锁,就是直接给put/get等方法加上synchronized,也就是给this加锁.
    给this加锁,这就意味着整个哈希表对象,就是一把锁.任何一个针对这个哈希表的操作,都会触发锁竞争.
    ConcurrentHashMap是给每个hash表中的"链表"进行加锁(多把锁).“锁桶”
    在这里插入图片描述
    上述的设定方式,既可以保证线程安全,又可以大大降低锁冲突的概率.只有同时进行两次的两次修改,恰好在修改同一个链表上的元素的时候,才会触发锁竞争.

  2. ConcurrentHashMap引入了CAS原子操作
    针对像size这样的操作,直接借助CAS完成,并不会加锁.

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

  4. ConcurrentHashMap针对hash表的扩容,进行了特殊的优化.
    普通hash表扩容,需要创建新的hash表,把元素都搬过去.这一系列操作,很有肯能就在一次put中完成了,这样就会使这次put的开销特别大,耗时非常长.
    ConcurrentHashMap针对hash扩容操作,使用了"化整为零"的思想.
    它不会在一次操作中,把所有的数据搬走,而是一次只搬运一部分.此时后续的每次操作,都会触发一部分key的搬运,最终把所有的key都搬运完成.等到全部元素都搬运完成后,再把老数组删掉.
    在这里插入图片描述
    当新旧数据同时存在的时候

    1. 插入操作,直接插入到新的空间中.
    2. 查询/修改/删除操作,都是需要同时查询旧的空间和新的空间的.

这里的扩容机制,跟B+树很像,B+树有一个优点,查询的开销非常稳定.

小小的补充,在往上查一些关于ConcurrentHashMap的资料的时候,可能会见到"分段锁"这样的说法.它属于ConcurrentHashMap早期的实现方式,它与现在的锁桶,思想上是一样的,但是实现上有差别.
"分段锁"把所有的桶,分段,每一段有一个锁(一个锁,管好几个链表)

它存在几个明显的问题:

  1. 它这里降低锁冲突,做的还不够彻底.
  2. 分段锁的实现方式,更复杂

咱们很多时候学习一些"原理"类的知识,一方面是能够有更好的理解,能够更深度的使用和排查问题.
另一方面,也是学习大佬们的设计理念,等到我们后续遇到了类似的场景,这些理念都可以给我们解决问题提供一些参考.

本文到这里就结束啦~

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

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

相关文章

使用Git进行版本控制:前端开发者的最佳实践

聚沙成塔每天进步一点点 本文回顾 ⭐ 专栏简介使用Git进行版本控制:前端开发者的最佳实践1. 引言2. Git的基本概念2.1 版本控制系统的作用2.2 Git 的基本操作 3. Git最佳实践3.1 使用有意义的提交信息3.2 小步提交,频繁提交3.3 使用分支进行开发3.4 代码…

SparkSQL SET和RESET

前言 我们在用代码写spark程序的时候,如果要设置一些配置参数,可以通过: SparkConf val conf = new SparkConf().setMaster("local[2]").setAppName("CountingSheep") val sc = new SparkContext(conf)spark-submit ./bin/spark-submit --name "M…

一个vue前端的例子(六)如何获取table一行的id

比如我们要删除列表一行 vue中template中的scope到底是个什么&#xff1f;_vue template scope-CSDN博客 <el-button click"edit_tool(scope.$index)" type"warning" icon"el-icon-edit">编辑</el-button> 获取列表下标

报错module ‘markdown‘ has no attribute ‘version‘解决方法

问题&#xff1a; 在配置环境时&#xff0c;遇到报错 module markdown has no attribute version 解决方法&#xff1a; 1.打开报错目录下的文件compat.py 2.将 markdown.version 更改为 markdown.__version__ (注意是双下划线&#xff09;

2005-2020年各省乡村高质量发展指数数据

2005-2020年各省乡村高质量发展指数数据 1、时间&#xff1a;2005-2020年 2、来源&#xff1a;农村年鉴、统计年鉴、人口和就业统计年鉴 2、指标&#xff1a;乡村高质量发展指数、每公顷农业机械动力&#xff08;千瓦/公顷&#xff09;、农田节水灌溉率、人均粮食产量&#…

OpenGL/GLUT实践:GLUT环境配置+实现反弹运动的三角形动画与键盘控制(电子科技大学信软图形与动画Ⅱ实验)

源码见GitHub&#xff1a;A-UESTCer-s-Code 文章目录 1 运行效果2 实验过程2.1 环境配置2.2 绘制三角形2.2.1 渲染函数2.2.2 主函数2.2.3 运行结果 2.3 调整窗口大小2.4 简单动画与按键控制2.4.1 简单旋转2.4.2 键盘控制 2.5 窗口反弹动画2.5.1 处理窗口大小变化2.5.2 渲染函数…

使用 `Vitesse Uni App` 创建微信小程序并配置 uview-plus 和 alovajs

使用 Vitesse Uni App 创建微信小程序 Vitesse Uni App&#xff1a;https://vitesse-docs.netlify.app/ UI&#xff1a;https://uview-plus.jiangruyi.com/components/intro.html 编辑器&#xff1a;VScode 安装 Volar&#xff08;Vue Offices&#xff09;插件 创建项目 pnpm …

并发编程:ReentrantLock

一、ReentrantLock 是什么&#xff1f; ReentrantLock 实现了 Lock 接口&#xff0c;是一个可重入且独占式的锁&#xff0c;和 synchronized 关键字类似。不过&#xff0c;ReentrantLock 更灵活、更强大&#xff0c;增加了轮询、超时、中断、公平锁和非公平锁等高级功能。 pu…

十一、C语言:字符串函数

目录 一、strlen 二、strcpy 三、strcat 四、strcmp 五、strstr 六、strtok 七、strerror 一、strlen 注意&#xff1a;strlen()函数的返回值是size_t&#xff0c;两个size_t相减仍为无符号数 int main() {char arr[10] "abc";char brr[10] "abc123&quo…

高基数 GroupBy 在 SLS SQL 中的查询加速

作者&#xff1a;顾汉杰&#xff08;执少&#xff09; 什么是高基数 GroupBy 简单来说&#xff0c;想要分析的数据&#xff0c;拥有超多的“唯一值计数”&#xff08;Distinct Count&#xff09;&#xff0c;而我们需要对这些数据进行分组分析&#xff08;如统计次数、排名、…

如何高效调试JavaScript代码:从Console到断点调试

聚沙成塔每天进步一点点 本文回顾 ⭐ 专栏简介如何高效调试JavaScript代码&#xff1a;从Console到断点调试1. 引言2. 基本调试工具概览2.1 浏览器开发者工具&#xff08;DevTools&#xff09;如何打开浏览器开发者工具&#xff1f; 2.2 常用的调试面板 3. 基本调试方法3.1 使用…

Springboot邮箱发送:如何快速集成并发信?

Springboot邮箱发送性能如何&#xff1f;怎么用SpringBoot发信&#xff1f; Springboot作为一款流行的Java框架&#xff0c;提供了简便的方式来集成邮件发送功能。AokSend将详细介绍如何快速集成Springboot邮箱发送功能&#xff0c;并实现高效的邮件发送。 Springboot邮箱发送…

考拉悠然产品发布会丨以悠然远智全模态AI应用平台探索AI行业应用

9月6日&#xff0c;成都市大模型新技术新成果发布暨供需对接系列活动——考拉悠然专场&#xff0c;在成都市高新区菁蓉汇盛大举行。考拉悠然重磅发布了悠然远智丨全模态AI应用平台&#xff0c;并精彩展示了交通大模型应用——智析快处等最新的AI产品和技术成果。 在四川省科学…

警用车载4G5G无线视频监控技术方案

目录 一、背景 二、系统方案设计 1.1系统架构 1.2车载终端 1.3监控中心 1.4传输网络 三、警用车载监控功能特点 2.1警用车载监控功能 &#xff08;1&#xff09;实时视频监控 &#xff08;2&#xff09;录像存储回放 &#xff08;3&#xff09;车载报警联动 &#…

如何清理C盘临时文件,释放10G以上空间

在我们日常使用电脑系统的过程中&#xff0c;想必大家都曾遇到过这样的情况&#xff1a;明明没有主动安装任何软件&#xff0c;然而 C 盘的可用空间却逐渐减少&#xff0c;甚至有时会收到系统发出的空间不足的提醒。 其实&#xff0c;在系统中存在这样一个至关重要的临时文件夹…

【Prometheus】PromQL聚合函数详细用法与应用实战

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

基于springboot+vue乒乓球预约管理系统

基于springbootvuemysql实现的乒乓球预约管理系统&#xff08;源码数据库部署视频&#xff09; ### 主要技术 SpringBoot、LayUI、Vue、MySQL ### 系统角色 用户、管理员 ### 系统功能 前台&#xff1a; 首页、乒乓球场、公告信息、留言反馈、个人中心 后台&#xff1a; …

Nginx解析:入门笔记

&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》《MYSQL》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 ✨欢迎加入探索nginx之旅✨ &#x1f44b; 大家好&#xff01;文本学习和探索Nginx配置。…

【C++ Primer Plus习题】13.2

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream> #include "classic.h&quo…

数据同步-Mysql同步到ElasticSearch

Mysql同步到ElasticSearch 数据同步1、定时任务2、双写3、MQ异步写入4、Logstash5、Canal 数据同步 一般情况下&#xff0c;如果做查询搜索功能&#xff0c;使用 ES 来模糊搜索&#xff0c;但是数据是存放在数据库 MySQL 里的&#xff0c;所以说我们需要把 MySQL 中的数据和 E…