ThreadLocal with null initial values - avoid create map and entry?

Peter Levart peter.levart at
Tue Nov 18 19:15:37 UTC 2014

Hi Bernd,

If you can swap the default ThreadLocal with your own implementation (a 
subclass of ThreadLocal), you can make it behave like you would like it 
to (It's a hack, I know ;-)

public class XThreadLocal<T> extends ThreadLocal<T> {

     private static class Null extends RuntimeException {
         static final Null INSTANCE = new Null();
         private Null() { super(null, null, false, false); }

     protected T initialValue() {
         throw Null.INSTANCE;

     public T get() {
         try {
             return super.get();
         } catch (Null n) {
             return null;

Regards, Peter

On 11/18/2014 04:09 PM, Bernd Eckenfels wrote:
> Hello,
> after eating something I understood what you mean :) Yes you are right,
> with the proposed change the initialValue would be called much more
> often if it returns (after longish compilation or in the trivial case)
> null.
> Not sure if this is a loss compared to not constructing the entry.
> Just some background, in the legacy code I have seen was a non-extended
> ThreadLocal() object bound to a instance variable. So this makes the
> situation even worse. Constructing ThreadLocal and not using get() is
> however not a problem as it does not register the map. So besides
> rewriting the code (to use a static) one approch of mine was to delay
> using set(). But as mentioned below, thats not possible when get()
> constructs the whole shebang.
> Gruss
> Bernd
> Am Tue, 18 Nov 2014
> 15:59:19 +0100 schrieb Bernd Eckenfels <ecki at>:
>> Am Tue, 18 Nov 2014 11:37:34 +0000
>> schrieb Tom Hawtin <tom.hawtin at>:
>>> On 18/11/2014 05:11, Bernd Eckenfels wrote:
>>>> Unfortunatelly the ThreadLocal#get() will call #setInitialValue()
>>>> in all cases, and this will in turn call createMap().
>>>> setInitialValue() could avoid to call createMap() when value is
>>>> null. This would reduce the number of created thread specific
>>>> maps and entries (and also weak references to the thread).
>>> There's no guarantee that the execution of initialValue was trivial
>>> even if it returns null.
>> Yes, but I dont think it has to be. As long as the initial value is
>> null it can be represented without any thread local map or entry. And
>> as there is no "hasEntry()" a application can only call get to probe
>> for existence (and this will in the current implementation always
>> created it).
>> So another option (but more complicated as it adds a new API function)
>> would be to have a hasEntry() (or similiar named) function which does
>> the same as get without calling the initialValue(). This would in this
>> case really differ for non-trivial initialValue() implementations,
>> thats why I would prefer to do it in get(). It needs to be checked if
>> get() gets too big for inlining, but the new if is not in a hot path.
>> Gruss
>> Bernd
>>> I don't know whether or not mixing up the execution paths through
>>> get would harm performance.
>>> Tom

More information about the core-libs-dev mailing list