[concurrency-interest] NullPointerExceptionin ThreadLocal$ThreadLocalMap.replaceStaleEntry

Raj qweries at gmail.com
Mon Jul 3 06:08:15 EDT 2006

To check if we are facing the "ThreadLocal.initialValue" creating a
new ThreadLocal bug, we added the following to ThreadLocal.java and
set it in the boot classpath.

public ThreadLocal()
   Throwable throwable = new Throwable();
   StackTraceElement[] traces = throwable.getStackTrace();
   for(int i=0; i<traces.length; i++)
      if(traces[i].getMethodName().equals("initialValue") ||
         traces[i].getMethodName().equals("get") ||

         PrintWriter writer =null;
            File tempFile = File.createTempFile("tlocal", ".txt", new
            FileOutputStream fileOutputStream = new FileOutputStream(tempFile);
            writer = new PrintWriter(new OutputStreamWriter(fileOutputStream));
         }catch(Throwable t){

The log files get generated in c:/temp when we run a simple test
client where "ThreadLocal.initialValue" is creating a new ThreadLocal.
This indicates the patched ThreadLocal is fine.

However, when we run our tests, we continue to get the original NPE
but no log file is being created by the patch. This indicates that
there might be some other situation where we get this NPE.

Would greatly appreciate any other thoughts in this regard.


On 6/30/06, Thomas Hawtin <tackline at tackline.plus.com> wrote:
> Doug Lea wrote:
> >
> > As Joe just mentioned, there was an unsupported usage (that
> > was not clearly documented as unsupported) of initialValue
> > methods recursively creating other ThreadLocals, that was
> > addressed for Mustang, and which might conceivably cause this.
> > It might not be too hard to look in your code to see if
> > there are any cases of this. Otherwise, offhand, this looks
> > like it might be a GC bug, but no one will be able to figure
> > it out unless they can replicate.
> Looking through the source, it does appear to be Bug 5025230 [1] as Joe
> says. However, this case is a bit more subtle than the scenario in the
> report. It appears that the nested thread-local initialisation causes
> some tidying of stale entries, which clears the slot about to be filled
> (probably on a complete rehash of the thread's table).
> Anyway, the result is the same. Initialising ThreadLocals within
> initialValue doesn't work in both 1.4.2_11 and 1.5.0_07. Currently you
> need mustang for it to work (or patch your own JRE - I believe there is
> a license to do this for internal use (IANAL)).
> Avoiding nested initialisation may be more difficult than it would first
> appear. As well as your own code in initialValue, you need to avoid
> using anyone else's code that might initiliase ThreadLocals. For
> instance, loading classes can cause ThreadLocals to initialise (that
> confused me briefly).
> You could try flushing out any ThreadLocals in every thread before using
> initialValue. However, the obvious safe approach is to override get in
> place of initialValue. Something like:
> public abstract class SaferThreadLocal/*<T>*/
> extends ThreadLocal/*<T>*/
> {
>     private static final Object UNINITIALIZED = new Object();
>     //@Override
>     protected final Object/*T*/ initialValue() {
>         return UNINITIALIZED;
>     }
>     protected abstract Object/*T*/ initialValueOverride();
>     //@SuppressWarnings("unchecked")
>     //@Override
>     protected final Object/*T*/ get() {
>         Object obj = super.get();
>         if (obj == UNINITIALIZED) {
>             obj = initialValueOverride();
>             super.set(obj);
>         }
>         return /*(T)*/obj;
>     }
> }
> (Disclaimer: code not tested, or even compiled.)
> Tom Hawtin
> [1] http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5025230

More information about the Concurrency-interest mailing list