<html><head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
</head>
<body>
Hi Danny,<br>
<br>
I see a couple of FJP workers that don’t seem to be carrying a
virtual thread blocked on clinit. Do you have the full stacktraces?
If available, the native stack traces would also be useful to verify
the entry point into the VM for the ones blocked at clinit.<br>
<br>
Thanks,<br>
Patricio<br>
<br>
<div class="moz-cite-prefix">On 11/2/25 9:44 PM, Danny Thomas wrote:<br>
</div>
<blockquote type="cite" cite="mid:CAABjz10cEfmG5qqGHDDjseWzxxdzOXd6SWbB1d_Qws1qN-1sEQ@mail.gmail.com">
<div dir="ltr">
<div class="gmail_quote gmail_quote_container">
<div dir="ltr">Hi folks,
<div><br>
We saw a clinit deadlock with Log4j 2 and virtual threads
recently. It's common for libraries to use a mix of static
and instance field loggers, so seems particularly
vulnerable to this kind of deadlock at startup.<br>
<br>
I don't recall reading what you have planned for clinit
pinning, so thought I'd pass on this potentially common
real-world deadlock and ask what you have in mind for
addressing this limitation.<br>
<br>
Cheers,<br>
Danny<br>
<br>
Pinned virtual thread holding the clinit lock:<br>
<br>
#265
"_internalWorkflowEvaluationQueue_2-workflow-evaluation-worker-0"
virtual<br>
java.base/jdk.internal.misc.Unsafe.park(Native
Method)<br>
java.base/java.lang.VirtualThread.parkOnCarrierThread(VirtualThread.java:675)<br>
java.base/java.lang.VirtualThread.park(VirtualThread.java:607)<br>
java.base/java.lang.System$2.parkVirtualThread(System.java:2643)<br>
java.base/jdk.internal.misc.VirtualThreads.park(VirtualThreads.java:54)<br>
java.base/java.util.concurrent.locks.LockSupport.park(LockSupport.java:219)<br>
java.base/java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:754)<br>
java.base/java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireShared(AbstractQueuedSynchronizer.java:1079)<br>
java.base/java.util.concurrent.locks.ReentrantReadWriteLock$ReadLock.lock(ReentrantReadWriteLock.java:738)<br>
org.apache.logging.log4j.core.util.internal.InternalLoggerRegistry.getLogger(InternalLoggerRegistry.java:113)<br>
org.apache.logging.log4j.core.util.internal.InternalLoggerRegistry.computeIfAbsent(InternalLoggerRegistry.java:196)<br>
org.apache.logging.log4j.core.LoggerContext.getLogger(LoggerContext.java:588)<br>
org.apache.logging.log4j.core.LoggerContext.getLogger(LoggerContext.java:561)<br>
org.apache.logging.log4j.core.LoggerContext.getLogger(LoggerContext.java:71)<br>
org.apache.commons.logging.LogAdapter$Log4jLog.<init>(LogAdapter.java:159)<br>
org.apache.commons.logging.LogAdapter$Log4jAdapter.createLog(LogAdapter.java:113)<br>
org.apache.commons.logging.LogAdapter.createLog(LogAdapter.java:95)<br>
org.apache.commons.logging.LogFactory.getLog(LogFactory.java:67)<br>
org.apache.commons.logging.LogFactory.getLog(LogFactory.java:59)<br>
org.springframework.data.redis.connection.convert.Converters.<clinit>(Converters.java:69)<br>
org.springframework.data.redis.connection.DefaultStringRedisConnection.<init>(DefaultStringRedisConnection.java:187)<br>
org.springframework.data.redis.connection.DefaultStringRedisConnection.<init>(DefaultStringRedisConnection.java:171)<br>
<br>
Unparked but unmounted virtual thread that's next in line
for read lock:<br>
<br>
#369
"_internalWorkflowEvaluationQueue_1-workflow-evaluation-worker-11"
virtual<br>
java.base/java.lang.VirtualThread.park(VirtualThread.java:596)<br>
java.base/java.lang.System$2.parkVirtualThread(System.java:2643)<br>
java.base/jdk.internal.misc.VirtualThreads.park(VirtualThreads.java:54)<br>
java.base/java.util.concurrent.locks.LockSupport.park(LockSupport.java:219)<br>
java.base/java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:754)<br>
java.base/java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireShared(AbstractQueuedSynchronizer.java:1079)<br>
java.base/java.util.concurrent.locks.ReentrantReadWriteLock$ReadLock.lock(ReentrantReadWriteLock.java:738)<br>
org.apache.logging.log4j.core.util.internal.InternalLoggerRegistry.getLogger(InternalLoggerRegistry.java:113)<br>
org.apache.logging.log4j.core.util.internal.InternalLoggerRegistry.computeIfAbsent(InternalLoggerRegistry.java:196)<br>
org.apache.logging.log4j.core.LoggerContext.getLogger(LoggerContext.java:588)<br>
org.apache.logging.log4j.core.LoggerContext.getLogger(LoggerContext.java:561)<br>
org.apache.logging.log4j.core.LoggerContext.getLogger(LoggerContext.java:71)<br>
org.apache.commons.logging.LogAdapter$Log4jLog.<init>(LogAdapter.java:159)<br>
org.apache.commons.logging.LogAdapter$Log4jAdapter.createLog(LogAdapter.java:113)<br>
org.apache.commons.logging.LogAdapter.createLog(LogAdapter.java:95)<br>
org.apache.commons.logging.LogFactory.getLog(LogFactory.java:67)<br>
org.apache.commons.logging.LogFactory.getLog(LogFactory.java:59)<br>
org.springframework.data.redis.connection.AbstractRedisConnection.<init>(AbstractRedisConnection.java:38)<br>
<br>
With the core workers all taken up by threads blocked on
clinit, preventing the continuation for the unparked
thread from running:<br>
<br>
"ForkJoinPool-2-worker-1" #266 [1606] daemon prio=5
os_prio=0 cpu=233.52ms elapsed=2547.44s
tid=0x00007fe9f38b4000 nid=1606 waiting on condition
[0x00007fe9ccde6000]<br>
java.lang.Thread.State: WAITING (parking)<br>
at
jdk.internal.misc.Unsafe.park(<a class="moz-txt-link-abbreviated" href="mailto:java.base@21.0.7.0.101/Native">java.base@21.0.7.0.101/Native</a>
Method)<br>
- parking to wait for <0x0000040009f6d730> (a
java.util.concurrent.ForkJoinPool)<br>
--<br>
"ForkJoinPool-2-worker-2" #267 [1607] daemon prio=5
os_prio=0 cpu=393.88ms elapsed=2547.44s
tid=0x00007fe9cdbf8000 [0x00007fe9cc465000]<br>
Carrying virtual thread #357<br>
at
jdk.internal.vm.Continuation.run(<a class="moz-txt-link-abbreviated" href="mailto:java.base@21.0.7.0.101/Continuation.java:251">java.base@21.0.7.0.101/Continuation.java:251</a>)<br>
- waiting on the Class initialization monitor for
org.springframework.data.redis.connection.convert.Converters<br>
--<br>
"ForkJoinPool-2-worker-3" #271 [1610] daemon prio=5
os_prio=0 cpu=308.69ms elapsed=2547.43s
tid=0x00007fe9cdbf8700 [0x00007fe9cc2e2000]<br>
Carrying virtual thread #367<br>
at
jdk.internal.vm.Continuation.run(<a class="moz-txt-link-abbreviated" href="mailto:java.base@21.0.7.0.101/Continuation.java:251">java.base@21.0.7.0.101/Continuation.java:251</a>)<br>
- waiting on the Class initialization monitor for
org.springframework.data.redis.connection.convert.Converters<br>
--<br>
"ForkJoinPool-2-worker-4" #272 [1611] daemon prio=5
os_prio=0 cpu=428.92ms elapsed=2547.43s
tid=0x00007fe9f5efdf00 [0x00007fe9cc261000]<br>
Carrying virtual thread #297<br>
at
jdk.internal.vm.Continuation.run(<a class="moz-txt-link-abbreviated" href="mailto:java.base@21.0.7.0.101/Continuation.java:251">java.base@21.0.7.0.101/Continuation.java:251</a>)<br>
- waiting on the Class initialization monitor for
org.springframework.data.redis.connection.convert.Converters<br>
--<br>
"ForkJoinPool-2-worker-5" #273 [1612] daemon prio=5
os_prio=0 cpu=347.62ms elapsed=2547.42s
tid=0x00007fe9cbef7000 nid=1612 waiting on condition
[0x00007fe9cbee0000]<br>
java.lang.Thread.State: WAITING (parking)<br>
at
jdk.internal.misc.Unsafe.park(<a class="moz-txt-link-abbreviated" href="mailto:java.base@21.0.7.0.101/Native">java.base@21.0.7.0.101/Native</a>
Method)<br>
- parking to wait for <0x0000040009f6d730> (a
java.util.concurrent.ForkJoinPool)<br>
--<br>
"ForkJoinPool-2-worker-6" #316 [1651] daemon prio=5
os_prio=0 cpu=286.41ms elapsed=2547.04s
tid=0x00007fe9db2f2000 [0x00007fe9ca6c5000]<br>
Carrying virtual thread #265<br>
at
jdk.internal.vm.Continuation.run(<a class="moz-txt-link-abbreviated" href="mailto:java.base@21.0.7.0.101/Continuation.java:251">java.base@21.0.7.0.101/Continuation.java:251</a>)<br>
at
java.lang.VirtualThread.runContinuation(<a class="moz-txt-link-abbreviated" href="mailto:java.base@21.0.7.0.101/VirtualThread.java:245">java.base@21.0.7.0.101/VirtualThread.java:245</a>)<br>
--<br>
"ForkJoinPool-2-worker-7" #317 [1652] daemon prio=5
os_prio=0 cpu=415.34ms elapsed=2547.03s
tid=0x00007fe9db2f2700 nid=1652 waiting on condition
[0x00007fe9ca645000]<br>
java.lang.Thread.State: WAITING (parking)<br>
at
jdk.internal.misc.Unsafe.park(<a class="moz-txt-link-abbreviated" href="mailto:java.base@21.0.7.0.101/Native">java.base@21.0.7.0.101/Native</a>
Method)<br>
- parking to wait for <0x0000040009f6d730> (a
java.util.concurrent.ForkJoinPool)<br>
--<br>
"ForkJoinPool-2-worker-8" #359 [1675] daemon prio=5
os_prio=0 cpu=108.86ms elapsed=2546.41s
tid=0x00007fe9f58fff00 [0x00007fe9c9a69000]<br>
Carrying virtual thread #270<br>
at
jdk.internal.vm.Continuation.run(<a class="moz-txt-link-abbreviated" href="mailto:java.base@21.0.7.0.101/Continuation.java:251">java.base@21.0.7.0.101/Continuation.java:251</a>)<br>
- waiting on the Class initialization monitor for
org.springframework.data.redis.connection.convert.Converters<br>
--<br>
"ForkJoinPool-2-worker-9" #360 [1676] daemon prio=5
os_prio=0 cpu=199.56ms elapsed=2546.41s
tid=0x00007fea12c4ed00 [0x00007fe9c99e8000]<br>
Carrying virtual thread #363<br>
at
jdk.internal.vm.Continuation.run(<a class="moz-txt-link-abbreviated" href="mailto:java.base@21.0.7.0.101/Continuation.java:251">java.base@21.0.7.0.101/Continuation.java:251</a>)<br>
- waiting on the Class initialization monitor for
org.springframework.data.redis.connection.convert.Converters<br>
</div>
</div>
</div>
</div>
</blockquote>
<br>
</body>
</html>