集合系列(十四) -ConcurrentHashMap详解

本文探讨了在多线程环境下如何避免使用HashMap导致的问题,介绍了ConcurrentHashMap的分段锁策略、JDK1.7和1.8版本的实现差异,以及红黑树优化。重点讲解了put、get和remove操作的并发控制机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、摘要

在之前的集合文章中,我们了解到 HashMap 在多线程环境下操作可能会导致程序死循环的线上故障!

既然在多线程环境下不能使用 HashMap,那如果我们想在多线程环境下操作 map,该怎么操作呢?

想必阅读过小编之前写的《HashMap 在多线程环境下操作可能会导致程序死循环》一文的朋友们一定知道,其中有一个解决办法就是使用 java 并发包下的 ConcurrentHashMap 类!

今天呢,我们就一起来聊聊 ConcurrentHashMap 这个类!

二、简介

众所周知,在 Java 中,HashMap 是非线程安全的,如果想在多线程下安全的操作 map,主要有以下解决方法:

  • 第一种方法,使用Hashtable线程安全类;
  • 第二种方法,使用Collections.synchronizedMap方法,对方法进行加同步锁;
  • 第三种方法,使用并发包中的ConcurrentHashMap类;

在之前的文章中,关于 Hashtable 类,我们也有所介绍,Hashtable 是一个线程安全的类,Hashtable 几乎所有的添加、删除、查询方法都加了synchronized同步锁!

相当于给整个哈希表加了一把大锁,多线程访问时候,只要有一个线程访问或操作该对象,那其他线程只能阻塞等待需要的锁被释放,在竞争激烈的多线程场景中性能就会非常差,所以 Hashtable 不推荐使用!

再来看看第二种方法,使用Collections.synchronizedMap方法,我们打开 JDK 源码,部分内容如下:

可以很清晰的看到,如果传入的是 HashMap 对象,其实也是对 HashMap 做的方法做了一层包装,里面使用对象锁来保证多线程场景下,操作安全,本质也是对 HashMap 进行全表锁!

使用Collections.synchronizedMap方法,在竞争激烈的多线程环境下性能依然也非常差,所以不推荐使用!

上面2种方法,由于都是对方法进行全表锁,所以在多线程环境下容易造成性能差的问题,因为hashMap 是数组 + 链表的数据结构,如果我们把数组进行分割多段,对每一段分别设计一把同步锁,这样在多线程访问不同段的数据时,就不会存在锁竞争了,这样是不是可以有效的提高性能?

再来看看第三种方法,使用并发包中的ConcurrentHashMap类!

ConcurrentHashMap 类所采用的正是分段锁的思想,将 HashMap 进行切割,把 HashMap 中的哈希数组切分成小数组,每个小数组有 n 个 HashEntry 组成,其中小数组继承自ReentrantLock(可重入锁),这个小数组名叫Segment 如下图:

当然,JDK1.7 和 JDK1.8 对 ConcurrentHashMap 的实现有很大的不同!

JDK1.8 对 HashMap 做了改造,当冲突链表长度大于8时,会将链表转变成红黑树结构,上图是 ConcurrentHashMap 的整体结构,参考 JDK1.7!

我们再来看看 JDK1.8 中 ConcurrentHashMap 的整体结构,内容如下:

JDK1.8 中 ConcurrentHashMap 类取消了 Segment 分段锁,采用 CAS + synchronized 来保证并发安全,数据结构跟 jdk1.8 中 HashMap 结构类似,都是数组 + 链表(当链表长度大于8时,链表结构转为红黑二叉树)结构。

ConcurrentHashMap 中 synchronized 只锁定当前链表或红黑二叉树的首节点,只要节点 hash 不冲突,就不会产生并发,相比 JDK1.7 的 ConcurrentHashMap 效率又提升了 N 倍!

说了这么多,我们再一起来看看 ConcurrentHashMap 的源码实现。

三、JDK1.7 中的 ConcurrentHashMap

JDK 1.7 的 Concur

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值