ConcurrentHashMap,非常体现水平的面试题

8、Concurrenthashmap

1.7版本:用segment对象 segment:小型的由链表组成的hashmap(数组)

当键值对进来就进行扩容, 转移到新数组。

1.8版本:不用segment对象 只有一个数组,直接进行扩容。1.8特性多线程扩容每一个线程同时负责不同位置的元素。

在创立一个concurrenthashmap时,如果需要指定长度可以如下:

ConcurrentHashmap chm=new ConcurrentHashmap(32);

但是在1.7环境下长度就是32,而1.8源代码如下 相当于会从原长度+原长度左移一位(一半)在+1。而长度会固定为2的次幂,所以实际长度会增加一倍 为64。

编辑

 此值被记录成sizeCtl

 编辑

 何时判断数组初始化:需看put方法源码可知

编辑

而这个initTable就是初始化的标志,所以调用put方法时就是数组初始化。而一但进行扩容时我们需要考虑到并发问题,而将sizeCtl改为-1就代表有数组正在初始化,这样就能解决并发问题(实在是妙,一个变量这么多用处)源代码实现如下:

编辑

就这一段代码,可以体现出作者的智慧与细节。完美地解释了sizeCtl四种值的情况。希望大家能通过自己的摸索来理解这一段代码,这样你的java水平会提高一个层次。这段代码有助于我们记忆sizeCtl的用处。

我们知道,当hashmap元素个数达到8个时会树化,这是一定的吗?

编辑

编辑

 源码可知,确实达到8个元素时会树化,但是再继续看如下源码:

编辑编辑

 这个treeifyBin方法显示了,如果链表长度小于这个参数(64)就不会进行树化,所以这也是一个细节点(面试会问!)。继续看这段代码,我们可以看到他加上了synchronized关键字,而他封装的对象是这个节点或者说就是这个桶,这又是一个考点。因为在HashTable中,我们加锁是整个数组加锁,而这里是对单个节点加锁,这又是一个区别所在。同时这也是为何他是Concurrent(并发),保证安全的一个操作。如果数组长度不够树化,他会进行一个扩容,清看tryPresize方法源码:编辑

可知,会扩容成两倍(跟之前长度为2的次幂的知识遥相呼应)。

其实内部还有更多的东西需要探讨,目前了解到这里可以应付大部分面试,之后会根据需求来决定是否进行内容扩充。

#秋招以来你最大的收获是什么#
全部评论
我在想,是不是你公司的面试题就是楼主你出的啊
1 回复 分享
发布于 2022-10-12 15:31 山西

相关推荐

牛客5655:其他公司的面试(事)吗
点赞 评论 收藏
分享
2 7 评论
分享
牛客网
牛客企业服务