**
1,头插法产生闭环的根本原因
什么是头插法:即next数据指向新数组节点,在新数组看来是插到了头部位置
**
主要发生环形就是因为这段代码:e.next = newTable[i],这个代码主要就是将数组二得数据放到了数组一节点新遍历的数据下面,代码表示就是,先把b赋值到新数组,然后找到c,把c的指针指向了新数组即b,那边其他线程进入该方法时,新线程在处理数组一的c节点时next就是b,而b的next也指向了c,形成环形
2、为啥使用扰动函数
什么是扰动函数:即hash方法
扰动函数是拿key的hashcode值和值的高16位进行亦或运算,降低碰撞几率,hashcode方法返回的int类型的散列数据
,大概有-21亿到21亿之间,数据非常大,但是在取数组下标时使用低位掩码,如默认hashmap数组长度16,则低位采用15,0000 0000 0000 000 1111 进行&运算,最后只取后四位,为了降低后四位的重复几率,采用高16位异或计算,打破低位重复规律
bucketIndex = indexFor(hash, table.length);
static int indexFor(int h, int length) {
return h & (length-1);
}
3、ConcurrentHashMap的分段锁的实现原理
首先分段锁是在1.7版本中,使用segment,ConcurrentHashMap中存放的数据是一段段的,即由多个Segment(段)组成的。每个Segment中都有着类似于数组加链表的结构。
static final class Segment<K,V> extends ReentrantLock implements Serializable
Segment继承了ReentrantLock,表明每个segment都可以当做一个锁
分段锁的优势在于保证在操作不同段 map 的时候可以并发执行,但是如果某段过大时会导致性能下降
1.8版本抛弃了分段锁,采用cas+synchonized,将锁对象细化到节点,同时使用cas乐观锁