Hi Patricio

In our scenario, we encountered a similar issue that appears to stem from the 
same root cause. I’m happy to share the case details.

The problem arises in our custom class loader: when we use Logback to log 
messages, Logback attempts to acquire a lock during write operations. 
Meanwhile, a virtual thread that’s in the process of class initialization gets 
pinned to its carrier thread. As a result, other virtual threads 
attempting to use the same class end up being blocked with the message:
"Waited for initialization of <class&gt; by other thread".

These waiting threads also get pinned to their carrier threads — but crucially, 
they do not enter&nbsp;<clinit&gt;. This creates a deadlock-like situation 
where:

One ForkJoinPool (FJP) worker thread is trying to acquire Logback’s lock.

Other FJP workers are waiting on a non-existent ObjectMonitor&nbsp;(likely due 
to the pinned thread holding the monitor and not progressing).

Interestingly, the stack traces appear to be in normal Java code, which makes 
the root cause non-obvious at first glance.
"ForkJoinPool-1-worker-28" #799 [828] daemon prio=5 os_prio=0 cpu=47855486.95ms 
elapsed=258235.59s allocated=42813G defined_classes=287 tid=0x00007f4803ad9000 
nid=828 waiting on condition &nbsp;[0x00007fd88ee65000]
&nbsp; &nbsp;java.lang.Thread.State: WAITING (parking)
&nbsp; &nbsp;Carrying virtual thread #101393
      at 
jdk.internal.vm.Continuation.run([email protected]/Continuation.java:252)
      - parking to wait for &nbsp;<0x00007f4892f23810&gt; (a 
java.util.concurrent.locks.ReentrantLock$NonfairSync)
      at 
java.lang.VirtualThread.runContinuation([email protected]/VirtualThread.java:299)
      at 
java.lang.VirtualThread$$Lambda/0x00007f484085cc48.run([email protected]/Unknown
 Source)
      at 
java.util.concurrent.ForkJoinTask$AdaptedRunnableAction.exec([email protected]/ForkJoinTask.java:1403)
      at 
java.util.concurrent.ForkJoinTask.doExec([email protected]/ForkJoinTask.java:387)
      at 
java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec([email protected]/ForkJoinPool.java:1313)
      at 
java.util.concurrent.ForkJoinPool.scan([email protected]/ForkJoinPool.java:1844)
      at 
java.util.concurrent.ForkJoinPool.runWorker([email protected]/ForkJoinPool.java:1809)
      at 
java.util.concurrent.ForkJoinWorkerThread.run([email protected]/ForkJoinWorkerThread.java:188)
&nbsp; &nbsp;"engine-44-111" #101393 Mounted virtual thread on 
"ForkJoinPool-1-worker-28" #799
      at jdk.internal.misc.Unsafe.park([email protected]/Native 
Method)
      - parking to wait for &nbsp;<0x00007fd984009f38&gt; (a 
java.util.concurrent.locks.ReentrantLock$NonfairSync)
      at 
java.lang.VirtualThread.parkOnCarrierThread([email protected]/VirtualThread.java:817)
      at 
java.lang.VirtualThread.park([email protected]/VirtualThread.java:755)
      at 
java.lang.System$2.parkVirtualThread([email protected]/System.java:2714)
      at 
java.util.concurrent.locks.LockSupport.park([email protected]/LockSupport.java:221)
      at 
java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire([email protected]/AbstractQueuedSynchronizer.java:754)
      at 
java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire([email protected]/AbstractQueuedSynchronizer.java:990)
      at 
java.util.concurrent.locks.ReentrantLock$Sync.lock([email protected]/ReentrantLock.java:153)
      at 
java.util.concurrent.locks.ReentrantLock.lock([email protected]/ReentrantLock.java:322)
      at 
ch.qos.logback.core.OutputStreamAppender.writeBytes(OutputStreamAppender.java:197)
      at 
ch.qos.logback.core.OutputStreamAppender.subAppend(OutputStreamAppender.java:231)
      at 
ch.qos.logback.core.rolling.RollingFileAppender.subAppend(RollingFileAppender.java:235)
      at 
ch.qos.logback.core.OutputStreamAppender.append(OutputStreamAppender.java:102)
      at 
ch.qos.logback.core.UnsynchronizedAppenderBase.doAppend(UnsynchronizedAppenderBase.java:84)
      at 
ch.qos.logback.core.spi.AppenderAttachableImpl.appendLoopOnAppenders(AppenderAttachableImpl.java:51)
      at ch.qos.logback.classic.Logger.appendLoopOnAppenders(Logger.java:270)
      at ch.qos.logback.classic.Logger.callAppenders(Logger.java:257)
      at 
ch.qos.logback.classic.Logger.buildLoggingEventAndAppend(Logger.java:421)
      at ch.qos.logback.classic.Logger.filterAndLog_0_Or3Plus(Logger.java:383)
      at ch.qos.logback.classic.Logger.info(Logger.java:591)
      at 
com.example.loader.PluginClassLoader.reverseLoadClassInternal(PluginClassLoader.java:217)
      at 
com.example.loader.PluginClassLoader.loadClass(PluginClassLoader.java:132)
      - locked <0x00007fd9b83dabc0&gt; (a 
com.example.loader.SharedPluginClassLoader)
      at 
java.lang.ClassLoader.loadClass([email protected]/ClassLoader.java:526)
      at com.example.MyExample.init(MyExample.java:34)
      at com.example.TaskHelper$$Lambda/0x00007f484149dec0.run(Unknown Source)
      at 
java.util.concurrent.ThreadPoolExecutor.runWorker([email protected]/ThreadPoolExecutor.java:1144)
      at 
java.util.concurrent.ThreadPoolExecutor$Worker.run([email protected]/ThreadPoolExecutor.java:642)
      at 
java.lang.Thread.runWith([email protected]/Thread.java:1607)
      at 
java.lang.VirtualThread.run([email protected]/VirtualThread.java:462)
      at 
java.lang.VirtualThread$VThreadContinuation$1.run([email protected]/VirtualThread.java:254)
      at 
jdk.internal.vm.Continuation.enter0([email protected]/Continuation.java:326)
      at 
jdk.internal.vm.Continuation.enter([email protected]/Continuation.java:317)


"ForkJoinPool-1-worker-23" #786 [828] daemon prio=5 os_prio=0 cpu=55.73ms 
elapsed=51857.88s allocated=1659K defined_classes=6 tid=0x00007fd92f9de800 
nid=828 in Object.wait() &nbsp;[0x00007fd88ef67000]
&nbsp; &nbsp;java.lang.Thread.State: RUNNABLE
&nbsp; &nbsp;Carrying virtual thread #1265
      at 
jdk.internal.vm.Continuation.run([email protected]/Continuation.java:255)
      at 
java.lang.VirtualThread.runContinuation([email protected]/VirtualThread.java:299)
      at 
java.lang.VirtualThread$$Lambda/0x00007fd93b7e4068.run([email protected]/Unknown
 Source)
      at 
java.util.concurrent.ForkJoinTask$RunnableExecuteAction.exec([email protected]/ForkJoinTask.java:1423)
      at 
java.util.concurrent.ForkJoinTask.doExec([email protected]/ForkJoinTask.java:387)
      at 
java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec([email protected]/ForkJoinPool.java:1313)
      at 
java.util.concurrent.ForkJoinPool.scan([email protected]/ForkJoinPool.java:1844)
      at 
java.util.concurrent.ForkJoinPool.runWorker([email protected]/ForkJoinPool.java:1809)
      at 
java.util.concurrent.ForkJoinWorkerThread.run([email protected]/ForkJoinWorkerThread.java:188)
&nbsp; &nbsp;"arkhouyi-houyi-pool-3-5" #1265 Mounted virtual thread on 
"ForkJoinPool-1-worker-23" #786
      at com.example.ExampleAccessor.getExample(ExampleAccessor.java:57)
      at com.example.TaskHelper$$Lambda/0x00007fd93c47e4d8.run(Unknown Source)
      at 
java.util.concurrent.ThreadPoolExecutor.runWorker([email protected]/ThreadPoolExecutor.java:1144)
      at 
java.util.concurrent.ThreadPoolExecutor$Worker.run([email protected]/ThreadPoolExecutor.java:642)
      at 
java.lang.Thread.runWith([email protected]/Thread.java:1607)
      at 
java.lang.VirtualThread.run([email protected]/VirtualThread.java:462)
      at 
java.lang.VirtualThread$VThreadContinuation$1.run([email protected]/VirtualThread.java:254)
      at 
jdk.internal.vm.Continuation.enter0([email protected]/Continuation.java:326)
      at 
jdk.internal.vm.Continuation.enter([email protected]/Continuation.java:317)


Xialin Liu
         Original
         
       
From: loom-dev-request <[email protected]&gt;
Date: 2025-11-04 02:08
To: loom-dev <[email protected]&gt;
Subject: loom-dev Digest, Vol 95, Issue 2





Hi&nbsp;Danny,

I&nbsp;see&nbsp;a&nbsp;couple&nbsp;of&nbsp;FJP&nbsp;workers&nbsp;that&nbsp;don?t&nbsp;seem&nbsp;to&nbsp;be&nbsp;carrying&nbsp;a&nbsp;virtual&nbsp;
thread&nbsp;blocked&nbsp;on&nbsp;clinit.&nbsp;Do&nbsp;you&nbsp;have&nbsp;the&nbsp;full&nbsp;stacktraces?&nbsp;If&nbsp;
available,&nbsp;the&nbsp;native&nbsp;stack&nbsp;traces&nbsp;would&nbsp;also&nbsp;be&nbsp;useful&nbsp;to&nbsp;verify&nbsp;the&nbsp;
entry&nbsp;point&nbsp;into&nbsp;the&nbsp;VM&nbsp;for&nbsp;the&nbsp;ones&nbsp;blocked&nbsp;at&nbsp;clinit.

Thanks,
Patricio

Reply via email to