ConcurrentHashMap –兼顾线程安全和运行效率

首先推荐一个网址(用漫画的形式讲解,图形结合通俗易懂很赞,文章的内容也是来源于此)

目录


ConcurrentHashMap与hashmap相比主要是多了一个segment的概念


  • segment是什么呢

    • Segment本身就相当于一个HashMap对象。
    • 同HashMap一样,Segment包含一个HashEntry数组,数组中的每一个HashEntry既是一个键值对,也是一个链表的头节点。
  • 单一的Segment结构如下:

    • 在ConcurrentHashMap中,这样的segment有2^n个,共同保存在一个名为segments的数组当中。
      ConcurrentHashMap --兼顾线程安全和运行效率
  • 整个ConcurrentHashMap的结构如下:

    • 可以说,ConcurrentHashMap是一个二级哈希表。在一个总的哈希表下面,有若干个子哈希表。
    • 这样的二级结构,和数据库的水平拆分有些相似。
      ConcurrentHashMap --兼顾线程安全和运行效率

ConcurrentHashMap这么设计有什么好处呢


  • 对比于hashtable,hashtable中采取synchronized包裹的方式使得达到线程安全的目的,但也因此极大的影响了他的速率
  • 而ConcurrentHashMap这么设计的话,可以只对单个segment加锁,这样的话,就能达到即线程安全又能保证速率

ConcurrentHashMap是如何做到线程安全的


  • 首先我们来看一下ConcurrentHashMap的几种并发读写
    • 不同Segment的并发写入:
      ConcurrentHashMap --兼顾线程安全和运行效率
    • 同一Segment的一写一读:
      ConcurrentHashMap --兼顾线程安全和运行效率
    • 同一Segment的并发写入:
      ConcurrentHashMap --兼顾线程安全和运行效率
  • 由此可见,ConcurrentHashMap当中每个Segment各自持有一把锁。在保证线程安全的同时降低了锁的粒度,让并发操作效率更高。

ConcurrentHashMap的读写详细过程


  • Get方法
    • 为输入的Key做Hash运算,得到hash值。
    • 通过hash值,定位到对应的Segment对象
    • 再次通过hash值,定位到Segment当中数组的具体位置。
  • Put方法
    • 为输入的Key做Hash运算,得到hash值。
    • 通过hash值,定位到对应的Segment对象
    • 获取可重入锁
    • 再次通过hash值,定位到Segment当中数组的具体位置
    • 插入或覆盖HashEntry对象。
    • 释放锁。

ConcurrentHashMap调用size方法


  • ConcurrentHashMap的Size方法是一个嵌套循环,大体逻辑如下
    • 遍历所有的Segment
    • 把Segment的元素数量累加起来。
    • 把Segment的修改次数累加起来
    • 判断所有Segment的总修改次数是否大于上一次的总修改次数。如果大于,说明统计过程中有修改,重新统计,尝试次数+1;如果不是。说明没有修改,统计结束
    • 如果尝试次数超过阈值,则对每一个Segment加锁,再重新统计。
    • 再次判断所有Segment的总修改次数是否大于上一次的总修改次数。由于已经加锁,次数一定和上次相等。
    • 释放锁,统计结束

相关文章:

  • 2022-12-23
  • 2021-08-30
  • 2021-11-20
  • 2022-12-23
  • 2022-12-23
  • 2021-08-14
  • 2021-12-08
猜你喜欢
  • 2021-07-16
  • 2021-11-22
  • 2022-12-23
  • 2021-11-30
  • 2021-09-14
  • 2022-12-23
相关资源
相似解决方案