震惊!ConcurrentHashMap里面也有死循环,作者留下的“彩蛋”了解一下...
发布网友
发布时间:2024-10-02 11:20
我来回答
共1个回答
热心网友
时间:2024-10-02 21:30
在探讨一个近期发现的JDK 8的BUG时,我们了解到Dubbo 2.7.7版本更新点的描述中,涉及到了与JDK相关的修复。这个BUG实际上是位于闻名的concurrent包中的computeIfAbsent方法。在JDK 9中被修复,修复者正是Doug Lea。由于ConcurrentHashMap就是Doug Lea的杰作,这个BUG可以被视作“谁污染谁治理”。为了理解这个BUG的成因,需要先了解computeIfAbsent方法的用途。
computeIfAbsent方法的目的是当Map中某个key对应的值不存在时,通过调用mappingFunction函数并返回该函数执行结果(非null)作为key的值。如初始化一个ConcurrentHashMap,第一次获取名为why的value,若未获取到,则返回null。接着调用computeIfAbsent方法获取null后,调用getValue方法,将返回值与当前key关联起来。因此,第二次获取时能拿到"why技术"。
了解了方法的用途,接下来揭示这个BUG。通过链接,我们看到具体的描述指向了concurrent包中的computeIfAbsent方法。这个BUG在JDK 9中被修复,修复人正是Doug Lea。要理解BUG,需要先了解这个方法的工作流程。在JDK 8之后,computeIfAbsent方法提供了第二个参数mappingFunction,该方法的含义是当前Map中key对应的值不存在时,调用mappingFunction函数,并将该函数的执行结果(非null)作为该key的value返回。
通过一系列代码演示,我们发现正常情况下,Map应该显示{AaAa=42,BBBB=42},但在JDK 8环境中运行给定的测试用例时,方法不会结束,而是陷入了死循环。这就是BUG。
在这个BUG被发现的过程中,提问的艺术也发挥了重要作用。Doug Lea和Pardeep在讨论中展示了提问和回答的策略。Pardeep提供的测试案例是转折点,它清晰地指出了问题所在。Doug Lea在问题提出后不久给出了回复,提出了解决问题的可能性,并且在后续的讨论中逐步明确了这个BUG的存在以及可能的解决方法。最终,这个BUG在JDK 9中得到了修复。
这个BUG的成因在于computeIfAbsent方法内部的另一个computeIfAbsent调用,导致了两个方法在处理相同的key时进入了死循环。在处理此BUG时,我们需要深入理解computeIfAbsent方法的工作流程。从代码分析中可以看出,当key为"AaAa"和"BBBB"时,它们在进行计算和存储操作时,由于key的哈希值相同,导致了循环条件无法满足break的情况,从而进入了死循环。
总结这个BUG,我们发现当key的哈希值相同时,多次调用computeIfAbsent方法会导致死循环。Doug Lea在JDK 9中通过增加判断条件,避免了这种循环情况,从而修复了这个BUG。对于使用JDK 8的开发者,可以通过将computeIfAbsent方法的使用方式调整为先调用get方法,再使用putIfAbsent方法,以此避免遇到这个BUG。此外,我们还提到了线程安全问题,即虽然ConcurrentHashMap本身是线程安全的,但在使用时仍需注意避免线程冲突,以确保程序的正确性。