ThreadLocal with examples in Java

Upasana | August 11, 2020 | 4 min read | 534 views | Multithreading and Concurrency


ThreadLocal provides a mechanism of maintaining thread confinement for a given object. which allows you to associate a per-thread value with a value-holding object.
ThreadLocal Java Docs

ThreadLocal class provides thread-local variables. These variables differ from their normal counterparts in that each thread that accesses one (via its get or set method) has its own, independently initialized copy of the variable.

Pattern to use ThreadLocal

ThreadLocal instances are typically private static fields in classes that wish to associate state with a thread (e.g., a user ID or Transaction ID).

For example, the class below generates counters local to each thread. A new copy ThreadLocalCounter is assigned the first time it invokes ThreadLocalCounter.get() and remains unchanged on subsequent calls.

ThreadLocalCounter class
public class ThreadLocalCounter {
    private int count;

    public ThreadLocalCounter(int count) {
        this.count = count;
    }

    public int increment() {
        return ++count;
    }

    private static final ThreadLocal<ThreadLocalCounter> threadLocal = ThreadLocal.withInitial(() -> new ThreadLocalCounter(0));

    public static ThreadLocalCounter get() {
        return threadLocal.get();
    }
}

This ThreadLocalCounter can be used by multiple threads to keep their own counter copy which is not visible to other threads.

ThreadLocalCounter
Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        ThreadLocalCounter threadLocalCounter = ThreadLocalCounter.get();
        while(true) {
            final int counter = threadLocalCounter.increment();
            doSomeWork(counter);
        }
    }

    private void doSomeWork(int counter) {
        //Dummy Work
    }
});
thread.start();
Garbage Collection Behaviour

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).

Benefits of using ThreadLocal

  1. It makes multi-threading easy by not sharing the state of an object across threads. Since state is not shared so you don’t need to synchronize it with other requests. Please be noted that ThreadLocal is not a substitute of synchronization, instead it isolates an object from being exposed to multiple threads. Something like this:

    Servlet filter with ThreadLocal
     doGet(HttpServletRequest req, HttpServletResponse resp) {
       User user = getLoggedInUser(req);
       StaticClass.getThreadLocal().set(user)
       try {
         doSomething()
         doSomethingElse()
         renderResponse(resp)
       }
       finally {
         StaticClass.getThreadLocal().remove()
       }
     }

    Now any code that requires access to current user object, can obtain the reference using below code:

    User user = StaticClass.getThreadLocal().get()
    where Static class is defined as:
    class StaticClass {
      static private ThreadLocal threadLocal = new ThreadLocal<User>();
    
      static ThreadLocal<User> getThreadLocal() {
        return threadLocal;
      }
    }

Usecase

  1. ThreadLocal is ideal for storing objects that are not thread-safe and object sharing across threads is not required. A good example is Hibernate Session which is not threadsafe and must not be shared across threads, so we can put Session into ThreadLocal and execute the transaction. In a servlet environment, this can happen in a filter which creates a new session for each request and commit the session after request is complete. Similar approach can be taken for JDBC connection.

  2. SimpleDataFormat is not a thread-safe class, so you can use ThreadLocal to keep a copy of it per thread, thus avoiding the need for synchronization. The other option could be to create a new object on each invocation which requires more resources compared to ThreadLocal approach.

    ThreadSafeDateFormat
    import java.text.SimpleDateFormat;
    import java.util.Date;
    
    public class ThreadSafeDateFormat {
        //SimpleDateFormat is not thread-safe, so give one instance to each thread
        private static final ThreadLocal<SimpleDateFormat> formatter = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy.MM.dd HHmm a"));
    
        public static String formatIt(Date date) {
            return formatter.get().format(date);
        }
    
        public static void main(String[] args) {
            final String formatIt = ThreadSafeDateFormat.formatIt(new Date());
            System.out.println("formatIt = " + formatIt);
        }
    }
  3. ThreadLocal is very useful in web applications, a typical pattern is to store the state of web request in ThreadLocal (usually in a servlet filter or spring interceptor) at the very start of the processing and then access this state from any component involved in request processing. Normally all the processing of a web request happens in a single thread. In-fact ThreadLocal is widely used in implementing application frameworks. For example, J2EE containers associate a transaction context with an executing thread for the duration of an EJB call. This is implemented using a static Thread-Local holding the transaction context.

  4. In creating a application that requires thread level stats collections for e.g. stress testing apps, performance monitoring app.

Issues with ThreadLocal

  1. ThreadLocal introduces hidden coupling among classes, which makes them hard to test and debug. So it should be used with care.

  2. It is easy to abuse ThreadLocal by treating its thread confinement property as a license to use global variables or as a means of creating “hidden” method arguments.

References

  1. Java Concurrency in Practice: Where author (Joshua Bloch) explains how Thread confinement is one of the simplest ways to achieve thread safety and ThreadLocal is more formal means of maintaining thread confinement.

  2. Discussion on SO - https://stackoverflow.com/questions/817856/when-and-how-should-i-use-a-threadlocal-variable


Top articles in this category:
  1. Blocking Queue implementation in Java
  2. Troubleshooting Deadlock in Java
  3. Custom Thread pool implementation in Java
  4. How will you implement your custom threadsafe Semaphore in Java
  5. Difference between Implementing Runnable and Extending Thread
  6. Producer Consumer Problem using Blocking Queue in Java
  7. Precision and scale for a Double in java

Recommended books for interview preparation:

Find more on this topic:
Buy interview books

Java & Microservices interview refresher for experienced developers.