ConcurrentHashMap面试问题

ConcurrentHashMap面试问题
1、JDK1.7中ConcurrentHashMap是通过分段锁+数组+链表来实现的,在ConcurrentHashMap中保存一个SegMent数组,Segment是继承ReentrantLock的可重入锁,也就是说对于每个Segment的操作可以通过加锁解锁的方式来保证线程的安全性。

2、JDK1.7ConcurrentHashMap中put数据的方式是通过hash的方式先找到插入entry在Segment数组中的位置,然后再通过Hash的方式找到entry在Segment中HashEntry中的位置,然后再执行插入到链表中,其中在对segment操作的时候会进行trylock如果获取到锁则执行插入,如果没有获取到锁则会重试3次还没获取到则用阻塞锁的方式获取锁,同时对链表中的节点进行删除操作时,需要将删除节点的前面所有节点复制一遍然后用头插法插入链表(原因是每个节点的next是final的不可修改)。

3、JDK1.7ConcurrentHashMap中get数据不需要加锁,如果读到的数据为空则会加锁后再读一遍,因为可能由于某个线程在删除某个节点导致读到的数据为空。(删除某个节点需要把前面所有节点复制一遍重新插入)。

4、扩容,不会对整个ConcurrentHashMap扩容只会针对某个segment扩容。

5、jdk1.8中ConcurrentHashMap的结构类似于Hashmap了也是用数组+链表+红黑树来实现的,不过它使用了CAS的方式和Synchronized加锁来保证线程的安全。

6、jdk1.8中ConcurrentHashMap的节点put流程:

(1)、如果数据没初始化则初始化

(2)、通过hash方式(与hashMap的hash方式类似只不过将hash值转化为正数)找到要put节点在数组中的位置,如果该位置为空,则通过CAS的方式插入/

(3)、如果当前节点正在扩容则该线程参与扩容完成

(4)、如果该位置有节点则通过synchronized加锁判断是如果该节点是链表则查找PUT,如果是红黑树则执行红黑树的PUT,之后通过bincount判断是否要将链表转化成红黑树。

(5)最后更新size值并且判断是否需要扩容。

7、ConcurrentHashMap扩容是允许多个线程并发进行扩容的,首先构造一个两倍于当前数据长度的数组,然后计算每个线程处理的槽的空间,然后通过死循环依次递减的方式对每个槽位进行判断知道有实际值的槽位,通过将槽位的每个节点分成2个链表将高位逻辑与计算为1的链表插入到i+n的位置,同时将旧的节点设置为占位符然后继续向前推进扩容操作。

8、ConcurrentHashMap的size方法是读取baseCount和CounterCell数据的总数量,因为是并发的也不一定正确;

9、ConcurrentHashMap的弱一致性主要表现在他的一些视图和迭代器上,通过迭代器遍历元素的时候如果之前的元素发生修改是不会抛出fail-fast异常的,后面的元素如果修改了会体现在迭代器遍历的结果上。

你可能感兴趣的:(hashmap)