Anirban B Anirban B - 7 months ago 17
Java Question

ThreadLocal InitialValue is called twice

I set the ThreadLocal initial value common for all threads. When calling constructor I changed the value and it printed correctly. But when starting the thread, it again changed to initial value? Is that expected? If yes, what is the explanation? Below is my two classes. Thanks in advance.


  1. MyRunnableThreadLocal.java

    public class MyRunnableThreadLocal implements Runnable {

    private ThreadLocal<String> threadLocal = new ThreadLocal<String>(){
    @Override protected String initialValue() {
    return "Thread Name not set yet";
    }
    };
    public MyRunnableThreadLocal(String threadName) {
    System.out.println(threadLocal.get());
    threadLocal.set(threadName);
    System.out.println("Thread name: " + threadLocal.get());
    }
    @Override
    public void run() {
    System.out.println(threadLocal.get());
    threadLocal.set(threadLocal.get() + " " + (Math.random() * 100D));
    try {
    Thread.sleep(2000);
    } catch (InterruptedException e) {
    }

    System.out.println(threadLocal.get());
    }


    }

  2. ThreadLocalTest.java

    public class ThreadLocalTest {

    public static void main(String[] args) {
    Thread t1 = new Thread(new MyRunnableThreadLocal("Thread 1"));
    Thread t2 = new Thread(new MyRunnableThreadLocal("Thread 2"));

    t1.start();
    t2.start();
    try {
    t1.join();
    t2.join();
    } catch (InterruptedException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }

    }

    }



Out Put:

Thread Name not set yet
Thread name: Thread 1
Thread Name not set yet
Thread name: Thread 2
Thread Name not set yet
Thread Name not set yet
Thread Name not set yet 20.24825634584746
Thread Name not set yet 59.67633602373702

Answer

The ThreadLocal is local to the thread in which the code runs (and the thread local object it is associated with.)

Thread Name not set yet <= runs in main
Thread name: Thread 1   <= runs in main for the first MyRunnableThreadLocal object
Thread Name not set yet <= runs in main for the 2nd MyRunnableThreadLocal object
Thread name: Thread 2   <= runs in main for the 2nd MyRunnableThreadLocal object
Thread Name not set yet <= runs in the first thread for the first MyRunnableThreadLocal
Thread Name not set yet <= runs in the 2nd thread for the 2nd MyRunnableThreadLocal
Thread Name not set yet 20.24825634584746  <= runs in the first thread for the first MyRunnableThreadLocal
Thread Name not set yet 59.67633602373702  <= runs in the 2nd thread for the 2nd MyRunnableThreadLocal

So you have three threads and two ThreadLocals. Your main uses both thread local and both threads you start have one value each.

Each time you have a new ThreadLocal object, or a new Thread, it has a new initial value.

What about setting the thread local value?

You only ever read a value you set once, before creating another ThreadLocal or using it in another thread.

If first four lines are run in main thread, then set in the line# 2 is not reflecting on line# 3?

Line #3 is a different ThreadLocal object in a different MyRunnableThreadLocal

If it is working on first MyRunnableThreadLocal object then why it is not reflecting on line# 5 or 6?

Line #5 and #6 are the first time those ThreadLocals have been used in those threads so they have an initial value.

Note: if you use InheritableThreadLocal it would do what you expect. This is because a new thread "inherits" the values set by it's parent thread.