Thread Locals (was Re: State of Loom)

Alan Bateman Alan.Bateman at oracle.com
Thu May 28 11:58:04 UTC 2020


On 27/05/2020 19:54, Brian Goetz wrote:
> There are two things being conflated regarding this use of TLs:
>
>  - What is the right mechanism (hint: TL is probably not it);
>  - Who should provide that mechanism
>
> I think Doug's main point here is that, if the JDK doesn't provide a 
> better way, people will continue using TL out of laziness, with bad 
> results.
>
> That's true, but I think we should focus on "what is the right 
> mechanism" first.
One thing to add is that we expect there will be migration paths for 
many existing usages of TL. May not be all cases initially but I think 
progress can be made.

One of the common usages of TLs is caching of objects that are expensive 
to create but are not thread safe. Many sightings of 
ThreadLocal<SimpleDateFormat> in this bucket. The migration path is 
DateTimeFormatter which can be created with a pattern to produce a 
immutable object that can be stored in a static final. We've already 
changed several cases in the loom repo to use DTF. Rémi brings up 
StringCoder which is one of several cases in the JDK where charset 
encoders/decoders are cached in TLs, same bucket. Some of this caching 
can go away, esp. with charsets that don't require an expensive lookup 
so they are cheap to create - ongoing work here and currently none of 
these cases are creating TLs when used in the context of virtual threads.

Using a TL as a flag to detect reentrancy. We have a couple of these in 
the JDK in places that lookup service providers where there is risk of 
recursive initialization. We've replaced these in the loom repo with a 
simple gate mechanism that just tracks the threads doing the 
initialization. Not a big bucket but there are ways to do this that 
don't need TLs or scope variables.

We've encountered several cases in enterprise libraries that use TLs to 
make available context to transient callees, some it due to callbacks. 
These libraries could have used a parameter to pass context around but 
that complicates some of the other code in the sandwich that doesn't 
know anything about the scope that it is being used in. Several of the 
cases that we've looked at support nested usages that translate to a 
stack of contexts (save old context, set TL to new context, do some 
action, restore TL to old context). A possible migration for these 
libraries to move to using explicit parameters of course.  Another is to 
treat them as candidates for the scope variables that is still under 
exploration and described in SoL part 2.

The JDK uses TLs to cache native resources in a few places. These 
resources are cached by carrier threads, not virtual threads, as it 
wouldn't scale. This only works because the code does not block and 
promises to not keep a reference to something on the carrier thread. If 
we do forced preemption then it require making use of the critical 
section support to temporarily pin the carrier thread. There may be a 
good case to replace these buffer/other caches with something better. 
That would at least help with the calls to expose something that is 
inheriting unsafe (too many potential reliability and security issues if 
you get it wrong).

I read the mails from Douglas as a plea for something to help creating a 
cache of mutable objects where it's critical to avoid contention. I read 
it that TLs are being used today as an approximation for CPU locals 
because there isn't anything better. This was the purposes of the 
processorid branch. It has a prototype that exposes a primitive to 
obtain the current CPU ID. It based on the Linux restartable sequences 
mechanism. There's a PoC of LongAdder in that branch but a lot more work 
is needed to see how it might be used in other advanced contexts.  So 
"approximation for CPU locals" is another set of cases that need 
attention, it's just hasn't been high priority of late.

-Alan



More information about the loom-dev mailing list