Class ThreadLocal<T>
THE VALUES LIVE ON THE THREAD, under a WEAK key, and both halves of that are load bearing.
What this replaces was a Map<Thread,T> plus a Set<Thread> held HERE and
written by every thread that touched the variable, with no synchronization of
any kind -- so two threads calling set at the same instant both wrote into one
java.util.HashMap. That map is open addressed with linear probing, and a torn
insert leaves a probe sequence with no terminator: every later lookup of an
absent key walks the whole table and never stops. MEASURED on a Codename One
backend server, which sets a ThreadLocal once per request: 14 threads spinning
inside java.util.HashMap.put at 1450% CPU, the process answering nothing and
never recovering. It needs no virtual threads and no collector involvement --
any two platform threads sharing a ThreadLocal can do it.
Keying off the thread fixes that, and there is no lock here because a thread only ever reads and writes its OWN table, which nothing else can reach.
THE KEY IS WEAK IN THE OTHER COPY, because the obvious version of that trade leaks the other way. It is STRONG here, and Entry says why: this port's java.lang.ref.Reference is a stub that answers null, so a weak key would discard every live binding. The rest of the reasoning is the other copy's. A long-lived worker thread that touches a short-lived ThreadLocal -- library or request code that creates them dynamically -- would pin the ThreadLocal AND its value until the thread died, however long ago the application dropped its last reference. The old layout at least let an unreachable ThreadLocal take its values with it. Holding the key weakly keeps that property and the new one: nothing here keeps a ThreadLocal alive, and an entry whose key has been collected is swept on the next access to this thread's table.
A LINEAR SCAN, not a hash table, and that is deliberate. A thread holds a handful of these in any real program, the scan is over an array of entries with no hashing and no probe sequence, and it is the sweep: every access already walks the whole table, so purging cleared keys costs nothing extra. It also cannot develop the pathology described above, which is what this class is recovering from.
-
Constructor Summary
Constructors -
Method Summary
-
Constructor Details
-
ThreadLocal
public ThreadLocal()
-
-
Method Details
-
initialValue
-
get
-
set
-
remove
public void remove()
-