Learnitweb

An introduction to ThreadLocal in Java

ThreadLocal class is one of the classes provided by Java which helps programmers in writing thread safe code. When sensitive data is accessed by multiple threads, it needs to be synchronized. ThreadLocal works in a different manner. Rather than synchronizing the shared data, we are providing each thread with its own copy of data.

ThreadLocal is used to store variables locally to a thread. When we create a ThreadLocal variable it means each thread has its own, independently initialized copy of the variable. So in simple terms we can say that two threads can not see each other’s ThreadLocal variables.

Each thread has an implicit copy of the ThreadLocal variable until it is alive. Once the thread is dead, all copies of ThreadLocal instances are eligible for garbage collection if no reference to the ThreadLocal instance exists.

ThreadLocal provides a different way of implementing thread safety. Each thread has an implicit copy of thread-local variable and therefore no need for synchronization. For our understanding we can say that thread-local variable is an extension of local variable. A local variable is visible in a block and a thread-local variable is visible in a thread.

1. When to use ThreadLocal?

If we are not writing multithreaded programs, we’ll rarely need to use ThreadLocal. But the benefits of ThreadLocal are such that it proves to be a very useful class for a programmer. A very common use of ThreadLocal is to associate state with a thread. For example, if we want to associate a user ID or a transaction ID with a thread, we can use thread-local variable. ThreadLocal variables are typically private static fields due to the same reason.

2. Create a ThreadLocal

Creating a ThreadLocal instance is just like creating instance of any other Java class. ThreadLocal provides a ThreadLocal() constructor to create a ThreadLocal instance.

private ThreadLocal threadLocal = new ThreadLocal();

3. Set ThreadLocal value

ThreadLocal class provides a method void set(T value) which can be used to set value of the current thread’s copy of this thread-local variable.

threadLocal.set("thread local value to set"); //threadLocal is ThreadLocal instance

4. Get ThreadLocal Value

ThreadLocal class provides a method T get() which can be used to get thread-local variable’s value.

String threadLocalValue = (String) threadLocal.get(); 

5. Remove ThreadLocal value

ThreadLocal class provides a method void remove() which can be used to remove the current thread’s value for this thread-local variable. After removing value if thread-local value is read, the value will be reinitialized by invoking its initialValue() method, unless the value is already set.

threadLocal.remove();

6. Set ThreadLocal initial value

ThreadLocal class has method protected T initialValue() which returns the current thread’s initial value for this thread-local variable. This method is usually called once per thread. This method is invoked first time when get() method is called. If we remove the value by invoking remove() and call get() again then initialValue() is invoked.

There are two ways to set the initial value:

6.1 Create a ThreadLocal subclass that overrides the initialValue() method.

// Thread local variable containing each thread's ID
     private static final ThreadLocal<Integer> threadId =
         new ThreadLocal<Integer>() {
             @Override protected Integer initialValue() {
                 return nextId.getAndIncrement();
         }
     };

6.2 Create a ThreadLocal with a Supplier interface implementation

In Java 8, withInitial() method was added which accepts a Supplier.

static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier)
private static final ThreadLocal<SimpleDateFormat> formatter = 
	ThreadLocal.<SimpleDateFormat>withInitial(() -> {return new SimpleDateFormat("yyyyMMdd HHmm");});

7. ThreadLocal example

import java.util.concurrent.atomic.AtomicInteger;

 public class ThreadId {
     // Atomic integer containing the next thread ID to be assigned
     private static final AtomicInteger nextId = new AtomicInteger(0);

     // Thread local variable representing thread's ID
     private static final ThreadLocal<Integer> threadId =
         new ThreadLocal<Integer>() {
             @Override protected Integer initialValue() {
                 return nextId.getAndIncrement();
         }
     };

     // Returns the current thread's unique ID
     public static int get() {
         return threadId.get();
     }
 }

8. ThreadLocal in shared threads

There are cases when threads are reused for example thread pools. Whenever there is a chance of reusing a thread, it is advised to remove the thread-local variable since the same thread may be used in the next request.

9. Conclusion

In this article we briefly discussed ThreadLocal in Java. We saw that each thread has its own, independently initialized copy of the variable. ThreadLocal provides a different approach for writing thread-safe programs.