写点什么

JDK1.8 ConcurrentHashMap 核心源码(面试重点)

  • 2023-12-06
    湖南
  • 本文字数:942 字

    阅读完需:约 3 分钟

JDK1.8 ConcurrentHashMap 核心源码(面试重点)

一、什么是 ConcurrentHashMap

ConcurrentHashMap 和 HashMap 一样,是一个存放键值对的容器。使用 hash 算法来获取值的地址,因此时间复杂度是 O(1)。查询非常快。

同时,ConcurrentHashMap 是线程安全的 HashMap。主要通过对指定的 Node 节点加锁,来保证数据更新的安全性。

二、ConcurrentHashMap 原理

在 JDK1.8 里面,ConcurrentHashMap 的数据结构为:数组+链表+红黑树。

其线程安全主要在两方面实现,一是数组使用 volatile 关键字,二是使用 CAS 自旋锁实现原子操作。

三、ConcurrentHashMap 源码详解

volatile:修饰节点数组,保证其可见性,禁止指令重排。

//volatile:禁止指令重排。transient volatile Node<K,V>[] table;
复制代码

DCL 操作:Double Check Lock 也是双重检查锁

一般情况下,大家在了解 DCL 时,都是通过单例模式的懒汉机制了解到的。

ConcurrentHashMap 中的数组有一个就够了,数组在 ConcurrentHashMap 中就是单例的。同时 ConcurrentHashMap 在刚刚 new 完之后,不会初始化数组,而是第一个添加数据时,才会初始化数组。

look 源码去:

发现初始化数组的方法是 initTable,在 initTable 的过程中,会涉及到一个属性,sizeCtl。

initTable 方法

CAS:实现并发原子操作

ConcurrentHashMap 之 put 操作

casTabAt 方法内部即 CAS 操作

static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i,                                        Node<K,V> c, Node<K,V> v) {   return U.compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v);}
复制代码

CAS(Compare-And-Swap):比较并交换。通过一个原子操作,用预期值去和实际值做对比,如果实际值和预期相同,则做更新操作。如果预期值和实际不同,就认为其他线程更新了这个值,不做更新操作。

总结

  • 做插入操作时,首先进入乐观锁,

  • 然后,在乐观锁中判断容器是否初始化,

  • 如果没初始化则初始化容器,

  • 如果已经初始化,则判断该 hash 位置的节点是否为空,如果为空,则通过 CAS 操作进行插入。

  • 如果该节点不为空,再判断容器是否在扩容中,如果在扩容,则帮助其扩容。

  • 如果没有扩容,则进行最后一步,先加锁,然后找到 hash 值相同的那个节点(hash 冲突),

  • 循环判断这个节点上的链表,决定做覆盖操作还是插入操作。

  • 循环结束,插入完毕。

最后

赠人玫瑰,手留余香~ LZ整理了一整套2023年最新的面试资料,如果有需要的小伙伴点击此处即可~

用户头像

java技术来一打~ 2023-12-01 加入

还未添加个人简介

评论

发布
暂无评论
JDK1.8 ConcurrentHashMap 核心源码(面试重点)_是月月啊2023_InfoQ写作社区