Java-多线程-深入理解ConcurrentHashMap
目录
- 什么是ConcurrentHashMap?
- 为什么有ConcurrentHashMap?
- 和HashMap区别
- 示例代码对比
- JDK7和JDK8中ConcurrentHashMap整体架构的区别
- JDK7中
- JDK8中
- ConcurrentHashMap的基本功能
- 在性能方面的优化
- 使用到的技术-CAS
- 概念说明
- 比较并交换的过程如下:
- 举例说明
- 底层原理
- 代码演示
- 总结

什么是ConcurrentHashMap?
ConcurrentHashMap(Concurrent:并存的,同时发生的;)
ConcurrentHashMap是Java中的一个线程安全的哈希表实现,它可以在多线程环境下高效地进行并发操作。
为什么有ConcurrentHashMap?
HashMap线程不安全,在多线程操作下可能会导致数据错乱
和HashMap区别

示例代码对比
使用HashMap和ConcurrentHashMap分别实现以下需求。
用30个线程向实例化出的map中插入key,value。每一次插入后,把map打印出来(for循环中sout)
key为for循环中的i值
value:使用UUID
public class HashMapUnsafeTest {public static void main(String[] args) throws InterruptedException {//演示HashMapMap<String, String> map = new HashMap<>();for (int i = 0; i < 30; i++) {String key = String.valueOf(i);new Thread(() -> {//向集合添加内容map.put(key, UUID.randomUUID().toString().substring(0, 8));//从集合中获取内容System.out.println(map);}, "").start();}}
}
public class ConcurrentHashMapSafe {public static void main(String[] args) throws InterruptedException {//演示ConcurrentHashMapMap<String, String> map = new ConcurrentHashMap<>();for (int i = 0; i < 30; i++) {String key = String.valueOf(i);new Thread(() -> {//向集合添加内容map.put(key, UUID.randomUUID().toString().substring(0, 8));//从集合中获取内容System.out.println(map);}, "").start();}}
}
多个线程同时对同一个集合进行增删操作导致错误

JDK7和JDK8中ConcurrentHashMap整体架构的区别
JDK7中

JDK8中

使用到的数据结构:数组、单向链表、红黑树

其中涉及到几个核心的参数
// 最大容量,2^30
private static final int MAXIMUM_CAPACITY = 1 << 30;
// 默认长度
private static final int DEFAULT_CAPACITY = 16;//遗留问题:为什么树化条件是8而取消树化条件却是6呢?
// 链表树化条件-是根据线程竞争情况和红黑树的操作成本进行设计的。
static final int TREEIFY_THRESHOLD = 8;
// 取消树化条件-为了避免过度的树化,防止内存占用过高。
static final int UNTREEIFY_THRESHOLD = 6; //链表结构中,每个节点只需要存储指向下一个节点的指针,而不需要存储节点的值。因此,链表只需要存储节点的引用,占用较少的内存空间。树结构中每个节点需要存储节点的值以及指向子节点的指针。
核心为Hash表,存在Hash冲突问题
使用链式存储方式解决冲突,冲突较多时,导致链表过长,查询效率较低,在JDK1.8中引入红黑树机制;
当数组长度大于64,且链表长度大于等于8时,单项链表转为红黑树
当链表长度小于6时,红黑树会退化为单向链表
ConcurrentHashMap的基本功能
本质上是一个HashMap,功能和HashMap是一样的
但ConcurrentHashMap在HashMap基础上提供了并发安全的实现,主要通过对node节点加锁实现,来保证对数据更新的安全性
锁粒度变小

在性能方面的优化
在JDK1.8中锁的粒度是数组中的某一个节点,在JDK1.7中锁定的是一个Segment,锁的范围更大
保证线程安全机制:
JDK7采用segment的分段锁机制实现线程安全,其中segment继承自ReentrantLock。
JDK8采用CAS(读)+Synchronized(写)保证线程安全。
锁的粒度:原来是对需要进行数据操作的Segment加锁,JDK8调整为对每个数组元素加锁(Node)。
链表转化为红黑树:定位结点的hash算法简化会带来弊端,Hash冲突加剧,因此在链表节点数量大于8时,会将链表转化为红黑树进行存储。
使用到的技术-CAS
概念说明
CAS的全称是:比较并交换(Compare And Swap)。在CAS中,有这样三个值:
V:要更新的变量(var)
E:预期值(expected)
N:新值(new)
比较并交换的过程如下:
判断V是否等于E,如果等于,将V的值设置为N;如果不等,说明已经有其它线程更新了V,则当前线程放弃更新,什么都不做。

举例说明
如果有一个多个线程共享的变量i原本等于5,我现在在线程A中,想把它设置为新的值6;
我们使用CAS来做这个事情;
首先我们用i去与5对比,发现它等于5,说明没有被其它线程改过,那我就把它设置为新的值6,此次CAS成功,i的值被设置成了6;
如果不等于5,说明i被其它线程改过了(比如现在i的值为2),那么我就什么也不做,此次CAS失败,i的值仍然为2。
底层原理
unsafe类——以下是类中涉及到的三个方法用来实现CAS效果的,这三个方法都是由native进行修饰的。具体的实现是由C++写的。

代码演示
没有使用CAS的代码
package com.example.threadpool.CAS;public class NoCASDemo {private static int counter = 0;public static void main(String[] args) throws InterruptedException {//线程一Thread thread1= new Thread(() -> {for (int i=0; i<10000;i++){counter++;}});//线程二Thread thread2= new Thread(() -> {for (int i=0; i<10000;i++){counter++;}});//执行线程thread1.start();thread2.start();//等待执行完线程1和2thread1.join();thread2.join();System.out.println("查看counter的总数"+counter);}}
使用CAS的代码
package com.example.threadpool.CAS;import java.util.concurrent.atomic.AtomicInteger;public class CASDemo {private static AtomicInteger counter = new AtomicInteger(0);public static void main(String[] args) throws InterruptedException {//线程一Thread thread1= new Thread(() -> {for (int i=0; i<10000;i++){increment();}});//线程二Thread thread2= new Thread(() -> {for (int i=0; i<10000;i++){increment();}});//执行线程thread1.start();thread2.start();//等待执行完线程1和2thread1.join();thread2.join();System.out.println("查看counter的总数"+counter.get());}public static void increment() {int currentValue;int newValue;do {//获取counter对象的value值currentValue = counter.get();//将counter对象的value值加1newValue = currentValue + 1;} while (!counter.compareAndSet(currentValue, newValue));}}
总结
总的来说,ConcurrentHashMap是Java中线程安全的哈希表实现,它通过使用锁分段技术来提供高效的并发性能。相比于Hashtable,ConcurrentHashMap在多线程环境下能够更好地支持高并发读写操作。
使用ConcurrentHashMap可以在多线程环境下安全地进行数据操作,而无需手动加锁。它通过将整个数据结构分成多个段来实现并发性能的提升,不同的线程可以同时访问不同的段,从而减少了线程之间的竞争。
ConcurrentHashMap的设计考虑了线程安全和性能的平衡。它提供了一些有用的方法,如putIfAbsent()、replace()等,可以方便地进行原子性的操作。此外,ConcurrentHashMap还支持遍历操作,可以通过迭代器安全地遍历其中的元素。
需要注意的是,虽然ConcurrentHashMap是线程安全的,但并不保证对于单个操作的原子性。如果需要进行复合操作,仍然需要额外的同步措施。
总的来说,ConcurrentHashMap是一个强大的线程安全的哈希表实现,适用于多线程环境下的高并发读写操作。它提供了高效的并发性能,可以提升系统的吞吐量和响应速度。
相关文章:
Java-多线程-深入理解ConcurrentHashMap
目录 什么是ConcurrentHashMap?为什么有ConcurrentHashMap?和HashMap区别示例代码对比 JDK7和JDK8中ConcurrentHashMap整体架构的区别JDK7中JDK8中 ConcurrentHashMap的基本功能在性能方面的优化使用到的技术-CAS概念说明比较并交换的过程如下࿱…...
没有配置redis但是报错连接redis失败
问题 没有配置redis但是报错连接redis失败 检查maven配置是否引入了redis依赖(可能是传递依赖,最好检查引进来的公共工程 解决办法 只需要在该工程application.yml文件中配置一下 redis就好,或者移除redis依赖 spring:redis:password: hos…...
剑指 Offer 04. 二维数组中的查找
力扣 在一个 n * m 的二维数组中,每一行都按照从左到右 非递减 的顺序排序,每一列都按照从上到下 非递减 的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。 示例: 现有矩阵 matrix…...
【工作中问题解决实践 九】Spring中事务传播的问题排查
最近在工作中遇到了两个关于事务操作的问题,顺便就着这两个问题又回顾了一遍Spring的事务相关的操作,想着一次性把这个问题研究明白了,后续使用事务的时候也能踏实点,让事务发挥真实的作用 什么是事务?什么是事务管理…...
【导出Word】如何使用Java+Freemarker模板引擎,根据XML模板文件生成Word文档(只含文本内容的模板)
这篇文章,主要介绍如何使用JavaFreemarker模板引擎,根据XML模板文件生成Word文档。 目录 一、导出Word文档 1.1、基础知识 1.2、制作模板文件 1.3、代码实现 (1)引入依赖 (2)创建Freemarker工具类 &…...
Devart dbForge Studio for MySQL Crack
Devart dbForge Studio for MySQL Crack dbForge Studio for MySQL是一个用于MySQL和MariaDB数据库开发、管理和管理的通用GUI工具。IDE允许您通过直观的界面创建和执行查询、开发和调试存储例程、自动化数据库对象管理、分析表数据。MySQL客户端提供了数据和模式比较和同步工具…...
C++、Java、JavaScript和python几个语句的对比介绍
C、Java、JavaScript和python几个语句的对比介绍 C、Java、JavaScript和python语言的for语句 C、Java和JavaScript的for语句的语法类似如下: for (初始条件; 循环条件; 循环后操作) { // 循环体代码 } 初始条件是在进入循环之前执行的语句,初始化循环…...
第20节 R语言医学分析:某保险医疗事故赔偿因素分析
文章目录 某保险医疗事故赔偿因素分析源码源文件下载某保险医疗事故赔偿因素分析 我们分析数据集“诉讼”的第一个方法是确定样本数量、变量类型、缩放/编码约定(如果有)用于验证数据清理。 接下来,数据集看起来很干净,没有缺失值,并且对于分类变量,将编码约定替换为实际…...
【雕爷学编程】MicroPython动手做(28)——物联网之Yeelight 4
知识点:什么是掌控板? 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片,支持WiFi和蓝牙双模通信,可作为物联网节点,实现物联网应用。同时掌控板上集成了OLED…...
解决K8S集群设置污点后,污点不生效,下发应用的问题
问题:在集群中部署了三个daemonset,一开始加了容忍Toleration,后边去掉Toleration后,还是一直往边缘节点上部署应用,非常离谱 解决:删掉Toleration后,需要把annotations一起删掉,因为…...
使用$test$plusargs提高RTL验收速度
文章目录 0 前言1 语法介绍2 示例3 多种情况的testbench怎么写 0 前言 这段时间在整合一个小ip,因为要验证每个feature是否可行,需要用testbench C语言的方式进行仿真验证,由于每种feature不仅要在C语言中修改寄存器配置,还要再…...
MySQL~mysql基础应用相关题
整卷阅览: 想要获取试卷原版请点击以下链接下载: https://download.csdn.net/download/qq_53142796/88168133https://download.csdn.net/download/qq_53142796/88168133 解题过程: 数据库:studentdb 数据库表如下: …...
Redis | 哨兵模式
Redis | 哨兵模式 1. 简介 Redis Sentinel(哨兵)是Redis提供的一种高可用性解决方案。它是一个独立的进程,用于监控和管理Redis主从模式的节点,并在主节点故障时自动进行故障转移。哨兵模式可以确保Redis集群的高可用性和数据一…...
MySQL语句性能分析与优化
目录 SQL性能分析 SQL执行频率 SQL慢查询日志 Profile Explain SQL优化 插入数据的优化 主键优化 Order By优化 Group By优化 Limit 优化 Count 优化 Update 优化 多表连接查询优化 SQL性能分析 通过SQL性能分析来做SQL的优化,主要是优化SQL的查询语…...
SpringBoot实现数据库读写分离
SpringBoot实现数据库读写分离 参考博客https://blog.csdn.net/qq_31708899/article/details/121577253 实现原理:翻看AbstractRoutingDataSource源码我们可以看到其中的targetDataSource可以维护一组目标数据源(采用map数据结构),并且做了路由key与目标…...
Linux(四)--包软件管理器与Linux上环境部署示例
一.包软件管理器【yum和apt】 1.先来学习使用yum命令。yum:RPM包软件管理器,用于自动化安装配置Linux软件,并可以自动解决依赖问题。通过yum命令我们可以轻松实现软件的下载,查找,卸载与更新等管理软件的操作。 最常用…...
自监督去噪:Recorrupted-to-Recorrupted原理分析与总结
文章目录 1. 方法原理1.1 相关研究1.2 研究思路1.3 小结 2. 实验结果3. 总结 文章地址: https://ieeexplore.ieee.org/document/9577798/footnotes#footnotes 参考博客: https://github.com/PangTongyao/Recorrupted-to-Recorrupted-Unsupervised-Deep-Learning-for-Image-Den…...
【css】css实现水平和垂直居中
通过 justify-content 和 align-items设置水平和垂直居中, justify-content 设置水平方向,align-items设置垂直方向。 代码: <style> .center {display: flex;justify-content: center;align-items: center;height: 200px;border: 3px…...
常见Charles在Windows10抓包乱码问题
废话不多说 直接开整 最近反复安装证书还是乱码 网上各种百度还是不行 首先计算机查看安装好的证书 certmgr.msc 找到并删除掉 重新安装证书 具体解决方法: 第一步:点击 【工具栏–>Proxy–>SSL Proxying Settings…】 第二步:配置…...
汽车维修保养记录查询API:实现车辆健康状况一手掌握
在当今的数字化世界中,汽车维修保养记录的查询和管理变得前所未有地简单和便捷。通过API,我们可以轻松地获取车辆的维修和保养记录,从而实现对手中车辆健康状况的实时掌握。 API(应用程序接口)是进行数据交换和通信的标…...
浏览器访问 AWS ECS 上部署的 Docker 容器(监听 80 端口)
✅ 一、ECS 服务配置 Dockerfile 确保监听 80 端口 EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]或 EXPOSE 80 CMD ["python3", "-m", "http.server", "80"]任务定义(Task Definition&…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
在WSL2的Ubuntu镜像中安装Docker
Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包: for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...
C++使用 new 来创建动态数组
问题: 不能使用变量定义数组大小 原因: 这是因为数组在内存中是连续存储的,编译器需要在编译阶段就确定数组的大小,以便正确地分配内存空间。如果允许使用变量来定义数组的大小,那么编译器就无法在编译时确定数组的大…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...
PHP 8.5 即将发布:管道操作符、强力调试
前不久,PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5!作为 PHP 语言的又一次重要迭代,PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是,借助强大的本地开发环境 ServBay&am…...
人工智能--安全大模型训练计划:基于Fine-tuning + LLM Agent
安全大模型训练计划:基于Fine-tuning LLM Agent 1. 构建高质量安全数据集 目标:为安全大模型创建高质量、去偏、符合伦理的训练数据集,涵盖安全相关任务(如有害内容检测、隐私保护、道德推理等)。 1.1 数据收集 描…...
android RelativeLayout布局
<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...
「Java基本语法」变量的使用
变量定义 变量是程序中存储数据的容器,用于保存可变的数据值。在Java中,变量必须先声明后使用,声明时需指定变量的数据类型和变量名。 语法 数据类型 变量名 [ 初始值]; 示例:声明与初始化 public class VariableDemo {publi…...
