ConcurrentHashMap

保证线程安全的原因

有线程安全隐患的变量使用volatile修饰,确保变量是从内存获取而不是变量的私有拷贝。

 

 

数据结构

JDK1.8 中的ConcurrentHashMap 选择了与 HashMap 相同的链表+红黑树结构;在锁的实现上,抛弃了原有的 Segment 分段锁,采用CAS + synchronized实现更加细粒度的锁。

CAS全称compare and swap(比较交换),执行函数CAS(V,E,N)

V: 需要改变的变量 -- value

E: 预期值 -- expect

N:新值 -- new

期望值和当前线程变量值相同,直接修改即可。

如果不同,则要重新读取变量值再看能不能修改。

 

 

将锁的级别控制在了更细粒度的哈希桶数组元素级别,也就是说只需要锁住这个链表头节点(红黑树的根节点),就不会影响其他的哈希桶数组元素的读写,大大提高了并发度。

 

 

 

put方法执行步骤

大致可以分为以下步骤:

  1. 根据 key 计算出 hash 值;
  2. 判断是否需要进行初始化;
  3. 定位到 Node,拿到首节点 f,判断首节点 f:
  • 如果为 null ,则通过 CAS 的方式尝试添加;
  • 如果为 f.hash = MOVED = -1 ,说明其他线程在扩容,参与一起扩容;
  • 如果都不满足 ,synchronized 锁住 f 节点,判断是链表还是红黑树,遍历插入;
  1. 当在链表长度达到 8 的时候,链表转换为红黑树。

源代码如下:

 
get方法

大致可以分为以下步骤:

  1. 根据 key 计算出 hash 值,判断数组是否为空;
  2. 如果是首节点,就直接返回;
  3. 如果是红黑树结构,就从红黑树里面查询;
  4. 如果是链表结构,循环遍历判断。

源代码如下:

 
 
参考文档:https://zhuanlan.zhihu.com/p/350099474

posted on 2023-01-11 20:42  周公  阅读(14)  评论(0编辑  收藏  举报

导航