Avoiding Read‑Modify‑Write Race Conditions in ConcurrentHashMap Using Lambda compute
The article explains how read‑modify‑write race conditions can occur when updating a ConcurrentHashMap from multiple threads, demonstrates a failing JUnit example, and shows how using the atomic compute method with a lambda expression eliminates the race and ensures thread‑safe updates.
java.util.concurrent provides two thread‑safe Map implementations, ConcurrentHashMap and ConcurrentSkipListMap, which are high‑performance but can still suffer from read‑modify‑write race conditions when used incorrectly.
In the “Wrong Demo” section a test updates a ConcurrentHashMap from three threads by reading a value, modifying it, and putting it back, which may cause the final count to be less than the expected number of updates, as shown by the JUnit assertion failure.
package com.fun;
import org.junit.Test;
import java.util.concurrent.ConcurrentHashMap;
import static org.junit.Assert.assertEquals;
public class TestFun {
public void update(ConcurrentHashMap<Integer, Integer> map) {
Integer result = map.get(1);
if (result == null) {
map.put(1, 1);
} else {
map.put(1, result + 1);
}
}
@Test
public void testUpdate() throws InterruptedException {
final ConcurrentHashMap<Integer, Integer> map = new ConcurrentHashMap<>();
Thread first = new Thread(() -> { update(map); update(map); update(map); update(map); update(map); });
Thread second = new Thread(() -> { update(map); update(map); update(map); update(map); update(map); });
Thread third = new Thread(() -> { update(map); update(map); update(map); update(map); update(map); });
first.start();
second.start();
third.start();
first.join();
second.join();
third.join();
assertEquals(15, map.get(1).intValue());
}
}To eliminate the race, the article recommends using the atomic compute method with a lambda expression, which performs read, modify, and write in a single synchronized step.
public void update(ConcurrentHashMap<Integer,Integer> map) {
map.compute(1, (key, value) -> {
if (value == null) {
return 1;
}
return value + 1;
});
}The source code of ConcurrentHashMap.compute is shown, illustrating how it acquires node‑level locks and updates the value atomically, ensuring thread safety.
Finally, the article notes that the lambda passed to compute runs under the map’s node lock, so no other thread may modify the same bucket concurrently.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
