百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

ConcurrentHashMap的实现原理(JDK1.7和JDK1.8)

yuyutoo 2025-03-26 18:54 30 浏览 0 评论

前言

今天就来介绍一下ConcurrentHashMap的实现原理(JDK1.7和JDK1.8)

哈希表

介绍

哈希表就是一种以键-值(key-indexed) 存储数据的结构,我们只要输入待查找的值即 key,即可查找到其对应的值。

哈希的思路很简单,如果所有的键都是整数,那么就可以使用一个简单的无序数组来实现:将键作为索引,值即为其对应的值,这样就可以快速访问任意键的值。这是对于简单的键的情况,我们将其扩展到可以处理更加复杂的类型的键。

链式哈希表

链式哈希表从根本上说是由一组链表构成。每个链表都可以看做是一个“桶”,我们将所有的元素通过散列的方式放到具体的不同的桶中。插入元素时,首先将其键传入一个哈希函数(该过程称为哈希键),函数通过散列的方式告知元素属 于哪个“桶”,然后在相应的链表头插入元素。查找或删除元素时,用同们的方式先找到元素的“桶”,然后遍历相应的链表,直到发现我们想要的元素。因为每个“桶”都是一个链表,所以链式哈希表并不限制包含元素的个数。然而,如果表变得太大,它的性能将会降低。


应用场景

我们熟知的缓存技术(比如 redis、memcached)的核心其实就是在内存中维护一张巨大的哈希表,还有大家熟知的 HashMap、CurrentHashMap 等的应用。

ConcurrentHashMap 与 HashMap 等的区别

HashMap

我们知道 HashMap 是线程不安全的,在多线程环境下,使用 Hashmap 进行 put 操作会引起死循环,导致 CPU 利用率接近 100%,所以在并发情况下不能使用 HashMap。

HashTable

HashTable 和 HashMap 的实现原理几乎一样,差别无非是

  • HashTable 不允许 key 和 value 为 null
  • HashTable 是线程安全的
    但是 HashTable 线程安全的策略实现代价却太大了,简单粗暴,get/put 所有相关操作都是 synchronized 的,这相当于给整个哈希表加了一把大锁。

多线程访问时候,只要有一个线程访问或操作该对象,那其他线程只能阻塞,相当于将所有的操作串行化,在竞争激烈的并发场景中性能就会非常差。

ConcurrentHashMap

主要就是为了应对 hashmap 在并发环境下不安全而诞生的, ConcurrentHashMap 的设计与实现非常精巧,大量的利用了 volatile,final, CAS 等 lock-free 技术来减少锁竞争对于性能的影响。

我们都知道 Map 一般都是数组+链表结构(JDK1.8 改为数组+红黑树)。


ConcurrentHashMap 避免了对全局加锁改成了局部加锁操作,这样就极大地提高了并发环境下的操作速度,由于 ConcurrentHashMap 在 JDK1.7 和 1.8 中的实现非常不同,接下来我们谈谈 JDK 在 1.7 和 1.8 中的区别。

JDK1.7 版本的 CurrentHashMap 的实现原理

在 JDK1.7 中 ConcurrentHashMap 采用了数组+Segment+分段锁的方式实现。

1.Segment(分段锁)
ConcurrentHashMap 中的分段锁称为 Segment,它即类似于 HashMap 的结构,即内部拥有一个 Entry 数组,数组中的每个元素又是一个链表,同时又是一个 ReentrantLock(Segment 继承了 ReentrantLock)。

2.内部结构
ConcurrentHashMap 使用分段锁技术,将数据分成一段一段的存储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问,能够实现真正的并发访问。如下图是 ConcurrentHashMap 的内部结构图:

从上面的结构我们可以了解到,ConcurrentHashMap 定位一个元素的过程需要进行两次 Hash 操作。
第一次 Hash 定位到 Segment,第二次 Hash 定位到元素所在的链表的头部。

3.该结构的优劣势
坏处:
这一种结构的带来的副作用是 Hash 的过程要比普通的 HashMap 要长
好处:
写操作的时候可以只对元素所在的 Segment 进行加锁即可,不会影响到其他的 Segment,这样,在最理想的情况下,ConcurrentHashMap 可以最高同时支持 Segment 数量大小的写操作(刚好这些写操作都非常平均地分布在所有的 Segment 上)。

所以,通过这一种结构,ConcurrentHashMap 的并发能力可以大大的提高。

JDK1.8 版本的 CurrentHashMap 的实现原理

JDK8 中 ConcurrentHashMap 参考了 JDK8 HashMap 的实现,采用了数组+链表+红黑树的实现方式来设计,内部大量采用 CAS 操作,这里我简要介绍下 CAS。

CAS 是 compare and swap 的缩写,即我们所说的比较交换。cas 是一种基于锁的操作,而且是乐观锁。在 java 中锁分为乐观锁和悲观锁。悲观锁是将资源锁住,等一个之前获得锁的线程释放锁之后,下一个线程才可以访问。而乐观锁采取了一种宽泛的态度,通过某种方式不加锁来处理资源,比如通过给记录加 version 来获取数据,性能较悲观锁有很大的提高。

CAS 操作包含三个操作数——内存位置(V)、预期原值(A)和新值(B)。 如果内存地址里面的值和 A 的值是一样的,那么就将内存里面的值更新成 B。CAS 是通过无限循环来获取数据的,若果在第一轮循环中,a 线程获取地址里面的值被 b 线程修改了,那么 a 线程需要自旋,到下次循环才有可能机会执行。

JDK8 中彻底放弃了 Segment 转而采用的是 Node,其设计思想也不再是 JDK1.7 中的分段锁思想。

Node:保存 key,value 及 key 的 hash 值的数据结构。其中 value 和 next 都用 volatile 修饰,保证并发的可见性。


Java8 ConcurrentHashMap 结构基本上和 Java8 的 HashMap 一样,不过保证线程安全性。

在 JDK8 中 ConcurrentHashMap 的结构,由于引入了红黑树,使得ConcurrentHashMap 的实现非常复杂,我们都知道,红黑树是一种性能非常 好的二叉查找树,其查找性能为 O(logN),但是其实现过程也非常复杂,而且可读性也非常差,Doug Lea 的思维能力确实不是一般人能比的,早期完全采用链表结构时 Map 的查找时间复杂度为 O(N),JDK8 中 ConcurrentHashMap在链表的长度大于某个阈值的时候会将链表转换成红黑树进一步提高其查找性能。


总结

其实可以看出 JDK1.8 版本的 ConcurrentHashMap 的数据结构已经接近 HashMap,相对而言,ConcurrentHashMap 只是增加了同步的操作来控制并发,从 JDK1.7 版本的 ReentrantLock+Segment+HashEntry,到 JDK1.8 版本中 synchronized+CAS+HashEntry+红黑树。

  1. 数据结构:取消了 Segment 分段锁的数据结构,取而代之的是数组+链表+红黑树的结构。
  2. 保证线程安全机制:JDK1.7 采用 segment 的分段锁机制实现线程安全,其中 segment 继承自 ReentrantLock。JDK1.8 采用 CAS+Synchronized 保证线程 安全。
  3. 锁的粒度:原来是对需要进行数据操作的 Segment 加锁,现调整为对每个数组元素加锁(Node)。
  4. 链表转化为红黑树:定位结点的 hash 算法简化会带来弊端,Hash 冲突加剧,因此在链表节点数量大于 8 时,会将链表转化为红黑树进行存储。
  5. 查询时间复杂度:从原来的遍历链表 O(n),变成遍历红黑树O(logN)。

感谢诸君的观看,文中如有纰漏,欢迎在评论区来交流。如果这篇文章帮助到了你,欢迎点赞关注。

相关推荐

Python操作Word文档神器:python-docx库从入门到精通

Python操作Word文档神器:python-docx库从入门到精通动动小手,点击关注...

Python 函数调用从入门到精通:超详细定义解析与实战指南 附案例

一、函数基础:定义与调用的核心逻辑定义:函数是将重复或相关的代码块封装成可复用的单元,通过函数名和参数实现特定功能。它是Python模块化编程的基础,能提高代码复用性和可读性。定义语法:...

等这么长时间Python背记手册终于来了,入门到精通(视频400集)

本文毫无套路!真诚分享!前言:无论是学习任何一门语言,基础知识一定要扎实,基础功非常的重要,找一个有丰富编程经验的老师或者师兄带着你会少走很多弯路,你的进步速度也会快很多,无论我们学习的目的是什么,...

图解Python编程:从入门到精通系列教程(附全套速查表)

引言本系列教程展开讲解Python编程语言,Python是一门开源免费、通用型的脚本编程语言,它上手简单,功能强大,它也是互联网最热门的编程语言之一。Python生态丰富,库(模块)极其丰富,这使...

Python入门教程(非常详细)从零基础入门到精通,看完这一篇就够

本书是Python经典实例解析,采用基于实例的方法编写,每个实例都会解决具体的问题和难题。主要内容有:数字、字符串和元组,语句与语法,函数定义,列表、集、字典,用户输入和输出等内置数据结构,类和对象,...

Python函数全解析:从入门到精通,一文搞定!

1.为什么要用函数?函数的作用:封装代码,提高复用性,减少重复,提高可读性。...

Python中的单例模式:从入门到精通

Python中的单例模式:从入门到精通引言单例模式是一种常用的软件设计模式,它保证了一个类只有一个实例,并提供一个全局访问点。这种模式通常用于那些需要频繁创建和销毁的对象,比如日志对象、线程池、缓存等...

【Python王者归来】手把手教你,Python从入门到精通!

用800个程序实例、5万行代码手把手教你,Python从入门到精通!...

Python从零基础入门到精通:一个月就够了

如果想从零基础到入门,能够全职学习(自学),那么一个月足够了。...

Python 从入门到精通:一个月就够了

要知道,一个月是一段很长的时间。如果每天坚持用6-7小时来做一件事,你会有意想不到的收获。作为初学者,第一个月的月目标应该是这样的:熟悉基本概念(变量,条件,列表,循环,函数)练习超过30个编...

Python零基础到精通,这8个入门技巧让你少走弯路,7天速通编程!

Python学习就像玩积木,从最基础的块开始,一步步搭建出复杂的作品。我记得刚开始学Python时也是一头雾水,走了不少弯路。现在回头看,其实掌握几个核心概念,就能快速入门这门编程语言。来聊聊怎么用最...

神仙级python入门教程(非常详细),从0到精通,从看这篇开始!

python入门虽然简单,很多新手依然卡在基础安装阶段,大部分教程对一些基础内容都是一带而过,好多新手朋友,对一些基础知识常常一知半解,需要在网上查询很久。...

Python类从入门到精通,一篇就够!

一、Python类是什么?大家在生活中应该都见过汽车吧,每一辆真实存在、能在路上跑的汽车,都可以看作是一个“对象”。那这些汽车是怎么生产出来的呢?其实,在生产之前,汽车公司都会先设计一个详细的蓝图...

学习Python从入门到精通:30天足够了,这才是python基础的天花板

当年2w买的全套python教程用不着了,现在送给有缘人,不要钱,一个月教你从入门到精通1、本套视频共487集,本套视频共分4季...

30天Python 入门到精通(3天学会python)

以下是一个为期30天的Python入门到精通学习课程,专为零基础新手设计。课程从基础语法开始,逐步深入到面向对象编程、数据处理,最后实现运行简单的大语言模型(如基于HuggingFace...

取消回复欢迎 发表评论: