On 01/07/2026 09:53, Roman Kennke wrote:
Hello,
Has it been discussed whether or not CarrierThreadLocal (currently in
JDK.internal.misc) could/should be public API? I think it may be useful.
The introduction of virtual threads has (more or less) silently changed the
semantics of ThreadLocal somewhat: before vthreads, ThreadLocal used to always
be local to platform threads (because that was the only kind of thread that
existed). With vthreads, ThreadLocal is now local to the VirtualThread, if the
code happens to run in a vthread, or otherwise local to the PlatformThread.
I think in most cases this may be the intended behavior. Although I might point
out that this can result in an enormous churn of ThreadLocal instances. I also
realize that many typical use-cases are better served by the new ScopeLocal and
that is great.
However, there are genuine use-cases where one might consciously want a
carrier-thread-local:
We (at Datadog) have this situation: we want to associate a context (think OTEL
span context) with (platform) threads, on the native side. And we need to
access that context from Java. And we do so by wrapping that native context in
a DirectByteBuffer. And because those accesses are rather frequent, we need to
preserve the DBB and stick it in a ThreadLocal. That used to be the right thing
to do - the native context is also thread-local after all. Now, with virtual
threads, that ThreadLocal suddenly becomes local to the vthread. Which means
that the DBB points to the native context of the first carrier thread that the
vthread accessed. As soon as the vthread gets unmounted and remounted to a
different carrier, it points to the wrong context. And even worse, when the
original carrier thread ends, it points to any unallocated or reallocated
memory and cause crashes and/or native heap corruptions. We have seen all of
those symptoms.
The right thing to do is to use CarrierThreadLocal to associate the DBB with
the correct platform thread. I realize that this might be a rather niche
use-case, but I would think that there are more situations where storing
information local to carrier threads might be useful.
So the question: would it be feasible to make CarrierThreadLocal a public API?
Or is that absolutely not possible, and should we rather stick with using it
via reflection and hope for the best?
I suppose an alternative would be to expose getCarrierThread() or similar from
virtual threads, but that would be less elegant (at least for our use).
WDYT?
It would be better to bring this to loom-dev where this topic has been
discussed several time. Our position in that project to date has been to
vehemently oppose exposing Java API that provide access to the carrier
or its thread locals -- is just too dangerous and potentially undermines
the integrity of the system.
It sounds like the scenario here is something that the native level that
assume a 1-1 relationship between Thread and native threads and that may
be something t probe/discuss further to see how such a system might work
with user defined threads.
-Alan