一文讲清楚ConcurrentHashMap原理,值得收藏。

ConcurrentHashMap原理是面试的一个高频知识点,这属于第一阶段的过招。

如果你答上来了,之后面试官可能会顺势追问一下,如何提高 ConcurrentHashMap 的插入效率?于是一个接着一个,连环问就开始了,直到探到你的老底才罢休。

今天我们用一篇文章把ConcurrentHashMap讲清楚,帮你在面试时不慌不忙,从容应对。

1、ConcurrentHashMap 原理概述

ConcurrentHashMap 是一个存储 key/value 对的容器,并且是线程安全的。我们先看 ConcurrentHashMap 的存储结构,如下图:

alt

这是经典的数组加链表的形式。并且在链表长度过长时转化为红黑树存储( Java 8 的优化),加快查找速度。

存储结构定义了容器的 “形状”,那容器内的东西按照什么规则来放呢?换句话讲,某个 key 是按照什么逻辑放入容器的对应位置呢?

我们假设要存入的 key 为对象 x,这个过程如下:

  1. 通过对象 x 的 hashCode () 方法获取其 hashCode;

  2. 将 hashCode 映射到数组的某个位置上;

  3. 把该元素存储到该位置的链表中。

从容器取数的逻辑如下:

  1. 通过对象 x 的 hashCode () 方法获取其 hashCode;

  2. 将 hashCode 映射到数组的某个位置上;

  3. 遍历该位置的链表或者从红黑树中找到匹配的对象返回。

这个数组 + 链表的存储结构其实是一个哈希表。

把对象 x 映射到数组的某个位置的函数,叫做 hash 函数。

这个函数的好坏决定元素在哈希表中分布是否均匀,如果元素都堆积在一个位置上,那么在取值时需要遍历很长的链表。

但元素如果是均匀的分布在数组中,那么链表就会较短,通过哈希函数定位位置后,能够快速找到对应的元素。

具体 ConcurrentHashMap 中的哈希函数如何实现我们后面会详细讲到。

扩容

我们大致了解了 ConcurrentHashMap 的存储结构。

那么我们思考一个问题,当数组中保存的链表越来越多,那么再存储进来的元素大概率会插入到现有的链表中,而不是使用数组中剩下的空位。

这样会造成数组中保存的链表越来越长,由此导致哈希表查找速度下降,从 O (1) 慢慢趋近于链表的时间复杂度 O (n/2),这显然违背了哈希表的初衷。

所以 ConcurrentHashMap 会做一个操作,称为扩容。

也就是把数组长度变大,增加更多的空位出来,最终目的就是预防链表过长,这样查找的时间复杂度才会趋向于 O (1)。

扩容的操作并不会在数组没有空位时才进行,因为在桶位快满时,新保存元素更大的概率会命中已经使用的位置,那么可能最后几个桶位很难被使用,而链表却越来越长了。ConcurrentHashMap 会在更合适的时机进行扩容,通常是在数组中 75% 的位置被使用时。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值