ConcurrentHashMap并发

2023-12-13 22:51:10

ConcurrentHashMap 并发

概述
jdk1.7概述

ConcurrentHashMap我们通过名称也知道它也是一个HashMap, 但是它底层JDK1.7与1.8的实现原理并不相同

在1.7中它内部维护一个Segment[]的数组, 加载因子0.75, 在创建一个长度为2的小数组HashEntry[], 在0索引处创建

image-20231213203430752

  • 根据键的哈希值计算出Sgement[]的索引
  • 如果为空,就创建一个长度为默认长度为2的数组
  • 再次利用键的哈希值计算出小数组应存入的索引(二次哈希)
  • 如果为空则直接添加

image-20231213203516205

image-20231213203537908

如果此时再来一个值地址值为索引4, 那么, 他会根据这个结构找到HashEntry中计算索引位置
如果为0, 则比较新旧值, 相同则不操作, 不相同则将新数据放在0索引处, 将老数据挂在新数据下
如果为1, 根据0.75加载因子应该先扩容2倍, 再将数据存入1索引

image-20231213203618787

1.7中ConncurrentHashMap的Segment[]的长度永远是16, 它扩容的是下面HashEntry[]

如果我们通过锁来限制线程的同步访问, HashMap将会锁住整个HashMap,而ConcurrentHashMap它只会锁住对应地址值的HashEntry[]

image-20231213203706406

总结:

  • 默认创建一个长度为16的Segment[],加载因子为0.75, 这个数组无法扩容
  • 还会同时创建一个长度为2的HashEntry[],将地址值赋值给0索引, 其他索引位置的元素都是null
  • 会根据键的hash值计算出大数组中的地址值,
  • 第一次,根据模版创建hashEntry[] 创建完毕,会二次哈希, 计算出在小数组中存入的位置
  • 如果根据键的hash值计算出大数组中的地址值不为null, 就会根据地址值找到下面的hashEntry[] 二次哈希计算存入位置,如果需要扩容则将hashEntry扩容两倍
  • 不需要扩容则比较, 没有元素就直接存, 有元素则比较, 如果不相同, 就会形成hash桶结构
jdk1.8 概述

底层结构: 数组+链表+红黑树

结合CAS机制+synchronized保证线程安全, 对比1.7可以看到初始化时候什么都没做

    public ConcurrentHashMap() {
    }

image-20231213203802435

如果为null,采用CAS算法获得地址值

image-20231213203821026

不为来就使用volatile关键字来获取地址值

image-20231213203909930

这里就越来越像我们之前看过的HashMap了

image-20231213203927432

总结:

  • 如果空参构造ConcurrentHashMap,则什么都不做, 只有在第一次添加元素的时候创建哈希表
  • 计算当前元素应该存在的索引
  • 判断索引为null, 将则利用CAS算法,将节点添加到数组中
  • 如果不为null, 则利用volatile关键字获得当前位置最新节点的地址值形成链表或者红黑树
  • 以链表或者红黑树节点为锁对象, 配合悲观锁(synchronized)保证多线程操作集合时的数据安全性
减小锁粒度

减小锁粒度是指缩小锁定对象的范围,从而减小锁冲突的可能性,从而提高系统的并发能力。减小锁粒度是一种削弱多线程锁竞争的有效手段,这种技术典型的应用是 ConcurrentHashMap(高性能的 HashMap)类的实现。对于 HashMap 而言,最重要的两个方法是 get 与 set 方法,如果我们对整个 HashMap 加锁,可以得到线程安全的对象,但是加锁粒度太大。Segment 的大小也被称为 ConcurrentHashMap 的并发度。

ConcurrentHashMap 分段锁

ConcurrentHashMap,它内部细分了若干个小的 HashMap,称之为段(Segment)。默认情况下一个 ConcurrentHashMap 被进一步细分为 16 个段,既就是锁的并发度。

如果需要在 ConcurrentHashMap 中添加一个新的表项,并不是将整个 HashMap 加锁,而是首先根据 hashcode 得到该表项应该存放在哪个段中,然后对该段加锁,并完成 put 操作。在多线程环境中,如果多个线程同时进行 put操作,只要被加入的表项不存放在同一个段中,则线程间可以做到真正的并行。

ConcurrentHashMap 是由 Segment 数组结构和 HashEntry 数组结构组成

ConcurrentHashMap 是由 Segment 数组结构和 HashEntry 数组结构组成。Segment 是一种可重入锁 ReentrantLock,在 ConcurrentHashMap 里扮演锁的角色,HashEntry 则用于存储键值对数据。一个 ConcurrentHashMap 里包含一个 Segment 数组,Segment 的结构和 HashMap类似,是一种数组和链表结构, 一个 Segment 里包含一个 HashEntry 数组,每个 HashEntry 是

一个链表结构的元素, 每个 Segment 守护一个 HashEntry 数组里的元素,当对 HashEntry 数组的数据进行修改时,必须首先获得它对应的 Segment 锁。

文章来源:https://blog.csdn.net/qq_24428851/article/details/134981573
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。