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