What is Thread Local?

Values stored in these variables are local to threads, which mean that each thread puts and gets its own variable value.

finding nemo seagulls GIF

Lets see one example:

public class TLocal implements Runnable {

    private ThreadLocal<String> localName = new ThreadLocal<String>();

    private String name;

    public void run() {
        String threadName = Thread.currentThread().getName();
        
        localName.set(threadName);
        name = threadName;
        
        System.out.println(threadName + " stored ["+threadName+"] in local variable and ["+threadName+"] in class variable");
        
        try {
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            //handle exception
        }
        
        System.out.println(threadName + " pulled ["+localName.get()+"] from local variable and ["+name+"] from class variable");
    }

    public static void main(String args[]) {
        TLocal o = new TLocal();
        Thread t1 = new Thread(o);
        Thread t2 = new Thread(o);
        t1.start();
        t2.start();
    }
}

Output:

Thread-0 stored [Thread-0] in local and [Thread-0] in class variable
Thread-1 stored [Thread-1] in local and [Thread-1] in class variable
Thread-0 pulled [Thread-0] from local variable and [Thread-1] from class variable
Thread-1 pulled [Thread-1] from local variable and [Thread-1] from class variable

If you check the above output, value stored in class variable is same for each coz Thread-1 overridden the class variable value which was earlier stored by Thread-0. Class variables of common object are common to threads.

In above example thread local variable value is not overridden, even though it is a class variable, because simply it is ThreadLocal.

Know Better Common Sense GIF by WylieFord.com

How to set default value for ThreadLocal variable?

Look at below code and output:

public class TLocal implements Runnable {

    private ThreadLocal<String> localName = new ThreadLocal<String>() {
        public String initialValue() {
            return "XXXX";
            }
    };

    private String name;

    public void run() {

        String threadName = Thread.currentThread().getName();
        System.out.println("Thread Local default value for thread: " + threadName + " is: " + localName.get());
        localName.set(threadName);
        name = threadName;
        System.out.println(threadName + " stored ["+threadName+"] in local and ["+threadName+"] in class variable");

        try {
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            //handle exception
        }

        System.out.println(threadName + " name retrieved ["+localName.get()+"] from local variable and ["+name+"] from class variable.");
    }

    public static void main(String args[]) {
        TLocal o = new TLocal();
        Thread t1 = new Thread(o);
        Thread t2 = new Thread(o);
        t1.start();
        t2.start();
    }
}

Output:

Thread Local default value for thread: Thread-0 is: XXXX
Thread-0 stored [Thread-0] in local and [Thread-0] in class variable
Thread Local default value for thread: Thread-1 is: XXXX
Thread-1 stored [Thread-1] in local and [Thread-1] in class variable
Thread-0 name retrieved [Thread-0] from local variable and [Thread-1] from class variable.
Thread-1 name retrieved [Thread-1] from local variable and [Thread-1] from class variable.

Are there any issues related to ThreadLocal?

1. Wrong usage may cause un-expected results.

You may get unexpected results when you are using ThreadLocal with ThreadPool. In the case of the thread pool, we may not be creating a new thread every time we need a thread, but we may be re-using free thread from thread pool.

Oh No Omg GIF by Friends

Consider you have written a logic, which says that for each incoming request, retrieve value from threadlocal:

  • If value retrieved is null then set threadlocal variable & perform some steps 
  • If value retrieve is not null perform some-other steps.

Now for initial few requests, this will work fine because for each new request a new thread will be allocated. But as soon as threads are started getting re-used, there might be issue as threadlocal variable will already be filled.

Think of some banking application, where for request coming from customer we do following:

  • We store account information in ThreadLocal variable.
  • For each request we check if thLocal.get():
    • If we get null, we store account info in thlocal and perform some steps.
    • If we get not null then we display account info to client.
  • Now let’s consider we forget to clear the threadlocal value at end of request.
  • Since request got a thread from threadpool, this means that this thread will be reused for another request.
  • Now some other user based on above logic will be able to see account info of some other user.

The solution to above problems is that clear the threadlocal variable at the end of each request.

2. Wrong usage of ThreadLocal may cause Out of Memory exception.

If we have single object of ThreadLocal, how each thread is actually able to get and set its own individual value? What is happening internally?

In very brief:

  • Each Thread class has a map which takes ThreadLocal object as a key and value you pass as a value.
    • Lets consider this map is reference by m1 variable.
  • When you call threadLocalObj.set(value1) method, what happens inside set is:
    • Get the current thread.
    • Get the current thread map reference (m1).
    • In the map returned above store threadLocalObj as key, and value1 as value.
  • Now you can easily imagine what could be happening when someone called get.

Check below diagram to understand this:

Genius Reaction GIF

Once again in terms of coding lets see ThreadLocal set and get method:
(Below code is not exact code, it is simplified version of real code)

class ThreadLocal {

    public void set(T value) {
        Thread t = Thread.currentThread();
        Map<ThreadLocal, Object> map = t.getMap();
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

    public void get() {
        Thread t = Thread.currentThread();
        Map<ThreadLocal, Object> map = t.getMap();
        if (map != null) {
            return map.get(this);
        }
        return setInitialValue();
    }

}

How to clear ThreadLocal variable?

Simple call remove() method on the variable.

clean chores GIF by Samm Henshaw

Till what time object set into ThreadLocal variable are alive?

Each thread holds an implicit reference to its copy of a thread-local variable as long as the thread is alive and the ThreadLocal instance is accessible; after a thread goes away, all of its copies of thread-local instances are subject to garbage collection (unless other references to these copies exist).

Why are we storing ThreadLocal values inside Thread only (inside Map object in Thread)?

This map object was specially added in Thread to store ThreadLocal values only because:

  • We don’t have to make map synchronised, as it contains single thread’s ThreadLocal objects and this thread is only going to set and get value from it.
  • Consider if were storing ThreadLocal’s of all threads in single Map, with key as Thread identifier. Since multiple threads will be trying to access this map, we have to synchronize it. Which means bad performance.

When to use Thread Local?

Consider one example; you have a Servlet which calls some business methods. Multiple users send their request and their request contains their username.

We want that the logs which are getting generated in servlet class or classes related for business logic should also have contains username, so that we can identify for which user these logs are.

One way to do this is that we extract username in servlet from request and pass this username to different methods which are getting called and print it in logs. But passing username through different methods and just for purpose of logs, doesn’t make sense.

What we need is ThreadLocal variable (public static) in a servlet. And we know that in case of servlets there is only one servlet object but each request is served by separate thread. Now when a thread will execute doGet or doPost method, it will retrieve the username and put it in ThreadLocal variable. And whenever thread reaches businessLogic related it class it can get username stored by calling ServletClass.thLocalVariable.get() method.

How can a thread use ThreadLocal variable in any class?

Simple make the variable as public static and you will be able to access it from any class using ClassName.localVariableName.


Rakesh Kalra

Hello, I am Rakesh Kalra. I have more than 15 years of experience working on IT projects, where I have worked on varied complexity of projects and at different levels of roles. I have tried starting my own startups, 3 of those though none of it were successful but gained so much knowledge about business, customers, and the digital world. I love to travel, spend time with my family, and read self-development books.

0 Comments

Leave a Reply