hashmap转红黑树的阈值为8_Java经典hash算法:HashMap深度解析

60d32ae14f0d1dbfc1a8cf844a0aeeea.png

Java并发编程系列

  1. Java经典同步锁:Synchronized关键字
  2. Java面试宝典:final语义深度分析
  3. 经典hash算法:HashMap深度解析

前言

在JDK1.6中,HashMap采用数组+链表实现,即使用链表处理冲突,同一hash值的节点都存储在同一链表。但是当某一个链表的元素较多时,通过key单链查找效率很低。

而在JDK1.8中,HashMap采用数组+链表+红黑树来实现,当链表长度超过阈值(TREEIFY_THRESHOLD=8)时,将链表转换为红黑树,这样节省查找时间。

8e446cedee25cf9d5261b14c72839ed4.png

红黑树链表阈值

本文采用JDK1.8说明。

概念

散列#Hash

散列就是把任意长度的输入,通过散列算法变成固定长度的输出.

Hash冲突

由于散列是不定长到定长,是一种压缩映射,输出值域小于输入值域,造成不同的输入值可能会有相同的输出值,这就是Hash冲突。

原理分析

hash存储位置

当程序调用put方法时,首先计算key的hash值,然后根据位运算算出是新Node节点还是红黑树(TreeNode)节点。

if ((p = tab[i = (n - 1) & hash]) == null)tab[i] = newNode(hash, key, value, null);

如果是红黑树,还需要判断key的equals方法,配合key的hash值,双管齐下,才能确定该节点的红黑树的位置

if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p;else if (p instanceof TreeNode) e = ((TreeNode)p).putTreeVal(this, tab, hash, key, value);

为什么红黑树要通过key的hash和equals方法来确定节点存储位置呢?

这是由于hash算法本身特性造成的。从Hash冲突的概念我们知道,通过Key算hash的存储位置,可能存在存储位置相同!

那如何解决key的hash冲突,保证唯一性呢?

Hash冲突

我们先了解下Java对equals方法和hashCode方法的两个约定:

当obj1.equals(obj2)为true时,obj1.hashCode() == obj2.hashCode()必须为true当obj1.hashCode() == obj2.hashCode()为false时,obj1.equals(obj2)必须为false

也就是说,如果hashCode不同,equals一定为false,如果hashCode相同,equals不一定为true。

理论上,hashCode可能存在冲突的情况,当冲突发生时,计算出的桶索引(bucketIndex)也是相同的,这时会取到桶索引位置已存储的元素最终通过equals来比较,equals方法就是哈希码碰撞时才会执行的方法。

基于以上两个约定,HashMap通过hashCode和equals判断Key是否已存在,如果hashCode和equals相等,则使用新V值替换旧V值如果hashCode相等当equals为false,则在JDK1.8中会使用红黑树法来解决冲突并返回旧V值,如果不存在 ,则存放新的键值对到桶索引位置。

一般情况下hash冲突在多线程高并发情况下比较明显。

我们知道JDK1.6是用equals比较来保证key的唯一性,但是某个Node节点(单链表结构)随着内部元素的增多,put和get的效率将越来越低,这里的时间复杂度是O(n),假如有1000个元素,put时需要比较1000次,效率很低。

通常情况下HashMap很少会用到equals方法,因为HashMap通过一个哈希表管理所有元素,当我们调用put存值时,HashMap首先会调用key的hashCode方法,获取哈希码,通过哈希码快速找到某个存放位置

总结

在多线程情况下,一般不会用HashMap,因为线程不安全,容易才产生脏数据。可以考虑用继承+锁或者ConcurrentHashMap代替。

关于我

我是Wooola,擅长微服务,分布式,并发,工作流。

有需要Java资料的同学,可以关注之后私信哈,回复“资料”可以免费领取Java BAT面试宝典/微服务/SpringCloud/SpringBoot等视频和资料,亲记得要点赞转发哦!!!

a2e5070db139297854b1bc8016f57f32.png
7cdff7edc2b6045492ffa47d0a03b815.png
1963b61851065011f2e1b432331d1216.png
fddab065b4c8b1f0daf0051520eda03f.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值