踏踏实实积累,不要浮躁!!!
1:为什么用HashMap
- HashMap 是一个散列桶(数组和链表),它存储的内容是键值对(key - value)
- HashMap采用了数组和链表的数据结构,能在查询和修改方面继承了数组的线性查找和链表的寻址修改
- HashMap是线程不安全的
- HashMap可以接受null键和值,而HashTable不能
解释为什么 HashMap可以接受 null 键和值
a:如果 k 值传入的是 null ,得到的hash 值是0
b:解析 HashMap put的源码逻辑 TODO
2:HashMap工作原理 ?
HashMap是基于hashing的原理,我们使用put(key,value)存储对象到HashMap中,使用 get(key)从HashMap中获取对象,调用Put方法时通过key的hashcode值找到Map数组的bucket位置来存储Node对象,具体流程如下
- 1:对key求Hash值,然后计算下标
- 如果没有碰撞直接放入桶中
- 如果发生碰撞,以链表的方式放在后面(用链表法来解决冲突)
- 如果链表长度超过阀值 TREEIFY_THRESHOLD(8) 会改造成 rbTree 当元素个数小于6的时候又转换成链表
- 如果节点已经存在,会替换原来的value值
- 如果 桶满了(初始容量16 * 负载因子0.75)就需要 resize操作 扩容到之前的两倍
3:有什么方法可以减少碰撞
- 扰动函数可以减少碰撞,尽量确保两个不相等的对象返回不同的hashcode,这样能减少碰撞的几率(扰动函数其实就是Hash函数内部的实现原理 TODO 里面具体的实现细节还不清楚)
- 使用不可变的,声明为final的对象做key,并且采用合适的hashcode和equals方法,在hashmap中Keyi值不可变是必要的
4:HashMap中 hash函数的实现
static final int hash(Object key) {
if (key == null){
return 0;
}
int h;
h=key.hashCode();返回散列值也就是hashcode
// ^ :按位异或
// >>>:无符号右移,忽略符号位,空位都以0补齐
//其中n是数组的长度,即Map的数组部分初始化长度
return (n-1)&(h ^ (h >>> 16));
}
解释:
1:求出key的hash值
2:将hash值高16位不变,低16位与高16位取异或
3:n表示桶的长度,通过(n -1) & 上面取的值 得到桶的序号 (其实就是取模这种方式更高效)
5:为什么不用二叉查找树,而用红黑树
红黑树可以解决 二叉查找树,在特殊情况下性能退化的问题(可能会退化成链表,查找的时间复杂度O(n)),
6:说说你对红黑树的见解
- 每个节点非黑即红
- 根节点是黑色的
- 如果节点是红色的,那么子节点一定时黑色的,反之不一定
- 每个叶子节点都是黑空
- 从根节点到叶子节点的路径,每条路径都包涵数目相同的黑色节点(黑色高度相同)
7:HashMap什么情况下会发生死循环
TODO
8:CurrentHashMap 原理
- 最大的特点是引入了 CAS (compare and swap)借助Unsafe来实现,采用cpu指令来保证 (CAS操作的过程,内存值V,旧的预期值A,要修改的新值B 当且仅当预期值A和内存值V相等时才会将B值更新到V值中去)
- 分段锁 降低了锁的粒度
- TODO
TODO
9:CAS操作会出现的问题
TODO
10:能用currenthashmap代替hashtable嘛 ?
可以的
11:currenthashmap在java8中有个bug,会进入死循环
原因是递归创建currenthashmap对象,该bug在1.9已经修复
场景重现如下
public class ConcurrentHashMapDemo{
private Map<Integer,Integer> cache =new ConcurrentHashMap<>(15);
public static void main(String[]args){
ConcurrentHashMapDemo ch = new ConcurrentHashMapDemo();
System.out.println(ch.fibonaacci(80));
}
public int fibonaacci(Integer i){
if(i==0||i ==1) {
return i;
}
return cache.computeIfAbsent(i,(key) -> {
System.out.println("fibonaacci : "+key);
return fibonaacci(key -1)+fibonaacci(key - 2);
});
}
}
TODO 原因解释 ???
12: JDK9怎么解决上面这个死循环的BUG ?