ConcurrentHashMap里面也有死循环

本文介绍了 JDK 8 中 ConcurrentHashMap 的一个已知 Bug,该 Bug 导致 computeIfAbsent 方法在特定条件下陷入死循环。通过分析 Dubbo 2.7.7 的更新和相关 Bug 报告,作者详细解释了问题的产生原因,指出问题在于递归调用 computeIfAbsent 时,两个具有相同哈希码的键导致的死循环。虽然在 JDK 9 中已被修复,但在 JDK 8 中需要注意避免这种情况。最后,作者讨论了如何避免此问题以及并发编程中线程安全的相关思考。
摘要由CSDN通过智能技术生成

这篇文章,聊一下我最近才知道的一个关于 JDK 8 的 BUG 吧。

首先说一下我是怎么发现这个 BUG 的呢?

大家都知道我对 Dubbo 有一定的关注,前段时间 Dubbo 2.7.7 发布后我看了它的更新点,就是下面这个网址:

https://github.com/apache/dubbo/releases/tag/dubbo-2.7.7

 

其中有 Bugfixex 这一部分:

 

每一个我都去简单的看了一下,其他的 Bugfixes 或多或少都和 Dubbo 框架有一定的关联性。但是上面红框框起来的部分完全就是 JDK 的 Bug 了。

 

所以可以单独拎出来说。

 

这个 Bug 我也是看到了这个地方才知道的,但是研究的过程中我发现,这个怎么说呢:我怀疑这根本就不是 Bug ,这就是 Doug Lea 老爷子在钓鱼执法。

 

为什么这样的说呢,大家看完本文就知道了。

 

Bug 稳定复现

 

点击 Dubbo 里面的链接,我们可以看到具体的描述就是一个链接:

 

 

打开这个链接:

https://bugs.openjdk.java.net/browse/JDK-8062841

 

 

我们可以看到:这个 Bug 是位于大名鼎鼎的 concurrent 包里面的 computeIfAbsent 方法。

 

这个 Bug 在 JDK 9 里面被修复了,修复人是 Doug Lea。

 

而我们知道 ConcurrentHashMap 就是 Doug Lea 的大作,可以说是“谁污染谁治理”。

 

 

要了解这个 Bug 是怎么回事,就必须先了解下面这个方法是干啥的:

java.util.concurrent.ConcurrentHashMap#computeIfAbsent

 

 

从这个方法的第二个入参 mappingFunction 我们可以知道这是 JDK 8 之后提供的方法了。

 

该方法的含义是:当前 Map 中 key 对应的值不存在时,会调用 mappingFunction 函数,并且将该函数的执行结果(不为 null)作为该 key 的 value 返回。

 

比如下面这样的:

 

 

初始化一个 ConcurrentHashMap ,然后第一次去获取 key 为 why 的 value,没有获取到,直接返回 null。

 

接着调用 computeIfAbsent 方法,获取到 null 后调用 getValue 方法,将该方法的返回值和当前的 key 关联起来。

 

所以,第二次获取的时候拿到了 “why技术”。

 

其实上面的代码的 17 行的返回值就是 “why技术”,只是我为了代码演示,再去调用了一次 map.get() 方法。

 

知道这个方法干什么的,接下来就带大家看看 Bug 是什么。

 

我们直接用这个问题里面给的测试用例,地址:

https://bugs.openjdk.java.net/secure/attachment/23985/Main.java

 

我只是在第 11 行和第 21 行加入了输出语句:

 

正常的情况下,我们希望方法正常结束,然后 map 里面是这样的:{AaAa=42,BBBB=42}

 

但是你把这个代码拿到本地去跑(需要 JDK 8 环境),你会发现,这个方法永远不会结束。因为它在进行死循环。

 

这就是 Bug。

 

提问的艺术

 

知道 Bug 了,按理来说就应该开始分析源码,了解为啥出现了会出现这个 Bug。

 

但是我想先插播一小节提问的艺术。因为这个 Bug 就是一个活生生的示例呀。

 

这个链接,我建议你打开看看,这里面还有 Doug Lea 老爷子的亲自解答:

https://bugs.openjdk.java.net/browse/JDK-8062841

 

首先我们看提出问题的这个人对于问题的描述(可以先不用细看,反正看着也是懵逼的):

 

通常情况下,被提问的人分为两类人:

 

  1. 遇到过并知道这个问题的人ÿ
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值