1、hashmap的基础:哈希表的简介
-
核心是基于哈希表的桶和链表,根据元素计算的hashcode放到不同的桶中去
-
O(1)的平均查找、删除时间
-
致命的缺陷是哈希值碰撞
2、java7中hashmap的实现:数组加链表
-
重要知识点:
-
初始容量
默认的初始容量16,每次增加两倍,容量总是2的幂
-
为什么数组大小一定要是2的幂?
当根据元素的哈希值为元素确定桶的时候,根据算法hash & (length-1)计算,因为length-1的值总是 11…11,任何数与1相与值还是1,此时获得的hash值的分布是相对均匀的。
-
负载因子
默认是0.75
-
哈希算法
-
扩容
-
当桶的个数超过阈值的时候,会进行扩容操作,此时会重新计算元素的hash值放到不同的桶中去。
-
低效
-
不安全(会发生死锁问题)
因为 扩容时采用头插法,在多线程情况下会形成环形链
-
-
3、java8中hashmap的改进和实现
-
实现基础:数组+链表+红黑树
-
扩容时插入顺序的改进
扩容时采用尾插法,
-
为什么超过8的时候会变成红黑树?
因为他符合泊松分布,超过8的概率已经很小了。当数量为6的时候会退化成链表。
-
怎么执行的put操作?
对key的hashcode做hash运算得到index,如果没有碰撞就直接放在桶里,如果碰撞了则以链表的形式存放在桶之后。如果碰撞导致链表过长则转换成红黑树,如果桶的数量超过了阈值则触发扩容。
-
怎么执行get操作?
首先根据key的值计算出hashcode找到相应的桶,然后和桶中的key进行equals比较找到对应的元素。
4、线程安全的map
-
hashtable
-
如何实现
对修改共享数据的方法加了synchronized方法来保证线程安全。
-
-
currenthashmap
-
如何实现
采用CAS+synchronized来保证并发安全性。
此时put的过程为:
根据 key计算出hashcode,判断是否需要初始化,如果为null表示当前位置可以写入数据,利用CAS尝试写入,失败则进行自旋,自旋一定次数后则进行锁升级,使用synchronized保证成功。
-