兄弟姐妹
HashMap:快,遍历顺序不确定,非线程安全
Hashtable:遗留类,线程安全,只有一个线程能写,并发性能较差
LinkedHashMap:记录插入顺序
ConcurrentHashMap:线程安全,分段锁
HashMap是什么
从结构实现来讲,HashMap是数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的,如下如所示。
HashMap结构
重要组成:
Node:实现了Map.Entry接口,本质是就是一个映射(键值对)。
Node[] table:哈希桶数组
int threshold:所能容纳的k-v对极限(table.length * load factor)
final float loadFactor:负载因子
int modCount:结构变化次数(put新的算,但是覆盖value不算)
int size:当前map中的k-v数量
设计思路
本质:空间成本和时间成本之间权衡
其实就是在根据实际情况确定哈希桶数组的大小,并在此基础上设计好的hash算法减少Hash碰撞。
那么通过什么方式来控制map使得Hash碰撞的概率又小,哈希桶数组(Node[] table)占用空间又少呢?答案就是好的Hash算法和扩容机制。
在HashMap中,哈希桶数组table的长度length大小必须为2的n次方(一定是合数),这是一种非常规的设计,常规的设计是把桶的大小设计为素数。相对来说素数导致冲突的概率要小于合数。主要是为了在取模和扩容时做优化,同时为了减少冲突,HashMap定位哈希桶索引位置时,也加入了高位参与运算的过程。
原理实现
1.确定哈希桶数组索引位置
hash()、取模运算的巧妙(来计算该对象应该保存在table数组的哪个索引处,当length = 2^n时,h&(length-1) = h%length,&比%更高效)
取模运算
2.分析HashMap的put方法
putVal()
put()
3.扩容机制
遍历旧的数组和所有node,重新计算hash,再refresh。
区别1.7和1.8(引入红黑树)
分布散列的时候
很极端
小结
1.扩容是特别消耗性能的,在能估算map大小的时候,可以初始化一个数值。
2.HashMap是线程不安全的,会造成死循环
3.jdk1.8中的红黑树对HashMap的性能优化
拓展
Hash哈希
- 可变数据类型的操作改变,导致哈希值的改变
ConcurrentHashMap
- 分段锁
- 对于size()的统计
网友评论