Files
java-interview-lab/hashmap-vs-concurrenthashmap/README.md
T

3.0 KiB

hashmap-vs-concurrenthashmap

Runnable companion for the ankurm.com article HashMap vs ConcurrentHashMap in Java: Internals, Thread Safety and Interview Answers.

Everything the article quotes about JDK internals was read out of the running JDK (reflection) and cross-checked against the java.util.HashMap and java.util.concurrent.ConcurrentHashMap source in the JDK's own lib/src.zip. Nothing is quoted from memory.

Versions

Component Version Verified against
JDK 25.0.5+8 (Temurin, LTS) java -version; source from this JDK's lib/src.zip
JUnit 6.1.3 maven-metadata.xml on Maven Central (latest GA at time of writing)
Maven 3.9.11 mvn -version

Quickstart

export JAVA_HOME=/path/to/jdk-25 && export PATH="$JAVA_HOME/bin:$PATH"
cd hashmap-vs-concurrenthashmap
mvn test                   # 7 tests, deterministic; rewrites output/01-04 and 06-08
./scripts/run-all.sh       # also regenerates output/05 (the measured, run-to-run-varying one)

First Maven run must be online. The tests reflect into JDK-internal fields, so surefire is configured with --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.util.concurrent=ALL-UNNAMED (see pom.xml). This is a learning aid; never reflect into JDK internals in production code.

Captured output (output/)

File Written by Deterministic?
01-jdk-constants.txt Jdk25ConstantsTest yes: TREEIFY_THRESHOLD, MIN_TREEIFY_CAPACITY, MOVED, TREEBIN ...
02-sizectl-lifecycle.txt SizeCtlTest yes: sizeCtl / threshold / baseCount through a map's life
03-treeify-compare.txt TreeifyCompareTest yes: 12 colliding keys, table length and bin type per insert
04-forced-lost-update.txt ForcedInterleavingTest yes: lost update with the bad timing forced by a latch
05-measured-lost-updates.txt LostUpdateDemo (via run-all.sh) no: counts differ on every run and machine; no test asserts them
06-recursive-update.txt RecursiveUpdateTest yes: computeIfAbsent recursion outcomes
07-null-handling.txt NullHandlingTest yes
08-atomic-updates-exact.txt AtomicUpdatesTest yes: merge/compute/locked total is exact every run

Source

File Purpose
Internals.java reflective readers: constants, sizeCtl, table, baseCount, threshold, bin class
CollidingKey.java key with a caller-chosen hashCode() to force one bin
LostUpdateDemo.java 8 threads x 200,000 increments of one key, 5 rounds, six variants
RecursiveUpdateDemo.java computeIfAbsent re-entering its own map

The older benchmark and null-handling demos the article also cites live in java-core-examples/hashmap-concurrenthashmap. For fail-fast iterators and bucket layout see the sibling collections module.