Why JDK 8’s computeIfAbsent Can Deadlock: A Deep Dive into the Bug

This article explores a JDK 8 bug in ConcurrentHashMap’s computeIfAbsent method that can cause an infinite loop, explains how the issue was discovered, reproduces it with test code, analyzes the root cause, and shows the fix introduced in JDK 9.

macrozheng
macrozheng
macrozheng
Why JDK 8’s computeIfAbsent Can Deadlock: A Deep Dive into the Bug

JDK Bug Overview

The author discovered a bug in JDK 8 while reviewing the Dubbo 2.7.7 release notes, where a red‑boxed entry in the Bugfixes list turned out to be a JDK issue rather than a Dubbo problem.

It concerns the java.util.concurrent.ConcurrentHashMap#computeIfAbsent method, which can enter an endless loop under certain conditions.

Reproducing the Bug

A test case from the OpenJDK bug tracker (JDK‑8062841) is used to demonstrate the problem. Running the test on JDK 8 shows that the method never returns because it gets stuck in a dead loop.

Understanding computeIfAbsent

The method’s purpose is to compute a value for a missing key using a mapping function and store the result if it is non‑null.

When the mapping function itself calls computeIfAbsent on the same map with a key that hashes to the same bucket, a recursive call occurs.

Root Cause Analysis

Both keys “AaAa” and “BBBB” produce the same hash after the spread operation (2031775), causing them to target the same bucket.

The first call inserts a ReservationNode as a placeholder. The second call encounters this placeholder, leading to a for‑loop at line 1649 that never breaks, resulting in an infinite loop.

Bug Fix in JDK 9

In JDK 9 the loop was fixed by adding a check for ReservationNode and throwing an IllegalStateException when such a node is encountered.

Takeaways

The bug illustrates that even thread‑safe containers like ConcurrentHashMap can be misused, leading to deadlocks or infinite loops.

When using computeIfAbsent, avoid recursive mappings that may target the same bucket.

For JDK 8 users, a workaround is to use get followed by putIfAbsent to achieve the same effect without triggering the bug.

public class Test {
    static Map<Integer, Integer> cache = new ConcurrentHashMap<>();

    public static void main(String[] args) {
        System.out.println("f(" + 14 + ") =" + fibonacci(14));
    }

    static int fibonacci(int i) {
        if (i == 0) return i;
        if (i == 1) return 1;
        return cache.computeIfAbsent(i, key -> {
            System.out.println("Slow calculation of " + key);
            return fibonacci(i - 2) + fibonacci(i - 1);
        });
    }
}
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JDKbugConcurrentHashMapcomputeIfAbsentthread-safety
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.