java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > java面试常见问题

java面试常见问题---ConcurrentHashMap

作者:兴趣使然の草帽路飞

ConcurrentHashMap是由Segment数组结构和HashEntry数组结构组成。Segment的结构和HashMap类似,是一种数组和链表结构,今天给大家普及java面试常见问题---ConcurrentHashMap知识,一起看看吧

1、请你描述一下ConcurrentHashMap存储数据结构是什么样子呢?

2、请问ConcurrentHashMap的负载因子可以新指定吗?

// 负载因子:表示散列表的填满程度~ 在ConcurrentHashMap中,该属性是固定值0.75,不可修改~

private static final float LOAD_FACTOR = 0.75f;

3、请问节点的 Node.hash 字段一般情况下必须 >=0 这是为什么?

或者说,Node 节点的 hash 值有几种情况?针对不同情况分析一下?

4、请你简述 ConcurrentHashMap 中 sizeCtl 字段的作用(不同情况下的含义)?

sizeCtr 即 Size Control,这个字段一定要仔细去理解一下,这个字段看不懂,可能会整个 ConcurrentHashMap 源码都一脸懵逼。

① sizeCtl == 0 时,表示的是什么情况?
② sizeCtl == -1 时,表示什么情况呢?
③ 初始化完散列表后,map.sizeCtl > 0 时,表示什么情况呢?
④ sizeCtl < 0 && sizeCtl != -1 时,代表什么情况呢?

5、请你说一下扩容标识戳的作用及其计算方式?

6、ConcurrentHashMap如何保证写数据线程安全?

这个问题其实就是问,向 ConcurrentHashMap 中添加数据确保线程安全是如何实现的。

添加数据具体流程如下:

7、描述一下ConcurrentHashMap中的hash寻址算法

ConcurrentHashMap 的寻址算法和 HashMap 差别不大:

8、ConcurrentHashMap如何统计当前散列表中的数据量?

ConcurrentHashMap 统计存储数据的数量是通过 addCount(long x, int check) 方法实现的,本质上是借助了 LongAdder 原子类。

ConcurrentHashMap为什么不采用 ConcurrentHashMap为什么不采用 AtomicLong 统计散列表数据量呢?统计散列表数据量呢?

那么 LongAdder 是如何保证大并发量下,性能依旧高效呢?

先看下LongAdder的操作原理图:

LongAdder采用"分段"的方式降低CAS失败的频次,典型的用空间换时间:

如当前类中base = 10,有三个线程进行CAS原子性的 加1操作,线程一执行成功,此时base=11,线程二、线程三执行失败后开始针对于Cell[]数组中的Cell元素进行加1操作,同样也是CAS操作,此时数组index=1index=2Cellvalue都被设置为了1。

执行完成后,统计累加数据:sum = 11 + 1 + 1 = 13,利用LongAdder进行累加的操作就执行完了,流程图如下:

9、触发扩容条件的线程,执行的预处理工作都有哪些?

10、旧散链表中迁移完毕后的桶,如何做标记?

ForwardingNode 有哪些作用?

11、如果散列表正在库容时,再来新的写入请求该如何处理呢?

这里要分两种情况考虑:

12、扩容期间,扩容工作线程如何维护sizeCtl的低16位呢?

13、当桶位中链表升级为红黑树,且当前红黑树上有读线程正在访问,那么如果再来新的写线程请求该怎么处理?

写线程会被阻塞,因为红黑树比较特殊,新写入数据,可能会触发红黑树的自平衡,这就会导致树的结构发生变化,会影响读线程的读取结果!

在红黑树上读取数据和写入数据是互斥的,具体原理分析如下:

反过来,当红黑树上有写线程正在执行写入操作,那么如果有新的读线程请求该怎么处理?

14、挂起等待的写线程后,什么时候将其唤醒再继续执行写操作呢?

15、总结

文章会不定时更新,有时候一天多更新几篇,如果帮助您复习巩固了知识点,后续会亿点点的更新!希望大家多多关注脚本之家的其他内容!

您可能感兴趣的文章:
阅读全文