A class initialization monitor is the JVM synchronization mechanism that threads wait on while a class initializer runs. Cyclic initialization can deadlock when two threads initialize mutually dependent classes. section 3.9.3
A cyclic initialization deadlock
Parallel initialization of A and B can leave A waiting for B while B waits for A. The application may freeze only under concurrency, making the defect intermittent and difficult to reproduce. section 3.9.3
"main" #1 prio=5 os_prio=0 …
java.lang.Thread.State: RUNNABLE
at com.example.B.<clinit>(Test.java:22)
- waiting on the Class initialization monitor for com.example.A
at com.example.Test.lambda$main$1(Test.java:8)
at com.example.Test$$Lambda$2/0x0000000800c00c18.run(Unknown Source)
…
"ForkJoinPool.commonPool-worker-1" #23 daemon prio=5 os_prio=0 …
java.lang.Thread.State: RUNNABLE
at com.example.A.<clinit>(Test.java:14)
- waiting on the Class initialization monitor for com.example.B
at com.example.Test.lambda$main$0(Test.java:8)
at com.example.Test$$Lambda$1/0x0000000800c00a00.run(Unknown Source)
The thread dump exposes the cycle directly: each thread waits on the other class's initialization monitor. section 3.9.3
Use jstack with the stuck process identifier and inspect <clinit> frames. Break cyclic initialization dependencies; static analyzers can detect the superclass-accessing-subclass pattern, but not every cycle. section 3.9.3
