loom-dev Digest, Vol 95, Issue 2
Patricio Chilano Mateo
patricio.chilano.mateo at oracle.com
Thu Nov 6 19:59:48 UTC 2025
Hi Xialin,
On 11/3/25 10:17 PM, Xialin Liu wrote:
>
> 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> by other thread"|.
>
> These waiting threads also get pinned to their carrier threads — but
> crucially, they do not enter|<clinit>|. 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 (likely due to the pinned thread holding the monitor
> and not progressing).
>
Yes, this is the issue addressed in JDK-8369238 for the common
initialization paths. (Note that the initialization lock of a class is
implemented using an internal Java monitor, so this is probably the one
you are observing).
> 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 [0x00007fd88ee65000]
> java.lang.Thread.State: WAITING (parking)
> Carrying virtual thread #101393
> at
> jdk.internal.vm.Continuation.run(java.base at 21.0.3.0.6.1-redjdk/Continuation.java:252)
> - parking to wait for <0x00007f4892f23810> (a
> java.util.concurrent.locks.ReentrantLock$NonfairSync)
> at
> java.lang.VirtualThread.runContinuation(java.base at 21.0.3.0.6.1-redjdk/VirtualThread.java:299)
> at
> java.lang.VirtualThread$$Lambda/0x00007f484085cc48.run(java.base at 21.0.3.0.6.1-redjdk/Unknown
> Source)
> at
> java.util.concurrent.ForkJoinTask$AdaptedRunnableAction.exec(java.base at 21.0.3.0.6.1-redjdk/ForkJoinTask.java:1403)
> at
> java.util.concurrent.ForkJoinTask.doExec(java.base at 21.0.3.0.6.1-redjdk/ForkJoinTask.java:387)
> at
> java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(java.base at 21.0.3.0.6.1-redjdk/ForkJoinPool.java:1313)
> at
> java.util.concurrent.ForkJoinPool.scan(java.base at 21.0.3.0.6.1-redjdk/ForkJoinPool.java:1844)
> at
> java.util.concurrent.ForkJoinPool.runWorker(java.base at 21.0.3.0.6.1-redjdk/ForkJoinPool.java:1809)
> at
> java.util.concurrent.ForkJoinWorkerThread.run(java.base at 21.0.3.0.6.1-redjdk/ForkJoinWorkerThread.java:188)
> "engine-44-111" #101393 Mounted virtual thread on
> "ForkJoinPool-1-worker-28" #799
> at
> jdk.internal.misc.Unsafe.park(java.base at 21.0.3.0.6.1-redjdk/Native Method)
> - parking to wait for <0x00007fd984009f38> (a
> java.util.concurrent.locks.ReentrantLock$NonfairSync)
> at
> java.lang.VirtualThread.parkOnCarrierThread(java.base at 21.0.3.0.6.1-redjdk/VirtualThread.java:817)
> at
> java.lang.VirtualThread.park(java.base at 21.0.3.0.6.1-redjdk/VirtualThread.java:755)
> at
> java.lang.System$2.parkVirtualThread(java.base at 21.0.3.0.6.1-redjdk/System.java:2714)
> at
> java.util.concurrent.locks.LockSupport.park(java.base at 21.0.3.0.6.1-redjdk/LockSupport.java:221)
> at
> java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(java.base at 21.0.3.0.6.1-redjdk/AbstractQueuedSynchronizer.java:754)
> at
> java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(java.base at 21.0.3.0.6.1-redjdk/AbstractQueuedSynchronizer.java:990)
> at
> java.util.concurrent.locks.ReentrantLock$Sync.lock(java.base at 21.0.3.0.6.1-redjdk/ReentrantLock.java:153)
> at
> java.util.concurrent.locks.ReentrantLock.lock(java.base at 21.0.3.0.6.1-redjdk/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> (a
> com.example.loader.SharedPluginClassLoader)
> at
> java.lang.ClassLoader.loadClass(java.base at 21.0.3.0.6.1-redjdk/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(java.base at 21.0.3.0.6.1-redjdk/ThreadPoolExecutor.java:1144)
> at
> java.util.concurrent.ThreadPoolExecutor$Worker.run(java.base at 21.0.3.0.6.1-redjdk/ThreadPoolExecutor.java:642)
> at
> java.lang.Thread.runWith(java.base at 21.0.3.0.6.1-redjdk/Thread.java:1607)
> at
> java.lang.VirtualThread.run(java.base at 21.0.3.0.6.1-redjdk/VirtualThread.java:462)
> at
> java.lang.VirtualThread$VThreadContinuation$1.run(java.base at 21.0.3.0.6.1-redjdk/VirtualThread.java:254)
> at
> jdk.internal.vm.Continuation.enter0(java.base at 21.0.3.0.6.1-redjdk/Continuation.java:326)
> at
> jdk.internal.vm.Continuation.enter(java.base at 21.0.3.0.6.1-redjdk/Continuation.java:317)
I’m confused about this stacktrace because I don’t see the <clinit> on
the stack. If you could send the stacktraces of all threads, including
the native stacks, that would be helpful.
Thanks,
Patricio
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/loom-dev/attachments/20251106/7fe09353/attachment-0001.htm>
More information about the loom-dev
mailing list