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的次幂的知识遥相呼应)。

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

  • 5
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值