[concurrency-interest] NullPointerExceptionin ThreadLocal$ThreadLocalMap.replaceStaleEntry

Taras Tielkes taras.tielkes at gmail.com
Fri Jun 30 13:30:16 EDT 2006


Doug Lea wrote:
> Taras Tielkes wrote:
>> T
>> Now for a bit off-topic...I heard that a new implementation of 
>> ThreadLocal will make it into Dolphin, eliminating both the lingering 
>> stale entries, and the value->key reference path limitation. Any 
>> thuth to this, or better, details?
>>
>
> I think that's the plan.
>
> Here's how I see some of the story behind it.
>
> 1. ThreadLocals were originally designed as a way to maintain
> very fast access (mainly by avoiding synchronization) to little
> bits of context needed mainly in infrastructure/middleware stuff.
> As an example, ReentrantReadWriteLock uses one to track reader
> recursion. The main design goals here are to make the common
> fast path very fast (usually less than a dozen simple instructions).
> And implicit limitations of not dealing well with cyclic garbage
> never even arose.
Were such consideration there at the beginning (1.1?), long before 
ReentrantReadWriteLock?

I've always been surprised (hearing about) such strong performance 
considerations, since the typical uses of ThreadLocal that I've seen 
(transacion, auth, causality contexts) aren't that demanding. Usually 
set at entry, removed at exit, with limited mutations in between (nested 
tx, role delegation, etc).
>
> 2. Web frameworks, especially, discovered that you could use
> ThreadLocals to maintain full session state more cheaply than
> any other way, basically by making everything a ThreadLocal.
> By not having programmers think about what would even make
> sense as a ThreadLocal, and instead using them for everything,
> ThreadLocal itself turns into a mini-garbage-collector. Which
> it will never do as well as platform-level GC. Even doing it
> as well as it does costs the "classic" uses a bit of performance,
> and doing it better will cost more.
>
There's something worse too: InheritableThreadLocal: There are 
components that set InheritableThreadLocals, and there are components 
creating threads, blissfully unaware of each other and a mix for 
disaster. The result is almost always an unGCable reference keeping a 
(perhaps huge) object graph in memory. The code setting the ITL just 
can't know when and where a new thread will be created.

A good example is a servlet that generates images (thus 
lazy-initializing the Java2D headless subsystem, to be specific, the 
sun.java2d.Disposer thread).
The first webapp to do this will leak a reference to any 
currently-for-that-thread ITL to the Disposer thread (which only shuts 
down when the JVM shuts down.

What about a method to forcefully clean the ThreadLocals for the current 
thread (and the CCL to) ?

> So the fun algorithmic issue here is how to make life better
> for both styles of use. Not knowing any better compromise, it
> may be that there is an additional SlowerButBetterAtGCThreadLocal
> class people can use when applicable.
>
Or a method to force cleanup. Frameworks usually know when a request is 
at the end of it's lifecycle.
Just curious, what is the pre-Thread amount of ThreadLocals you're 
optimizing for?

-tt


More information about the Concurrency-interest mailing list