The Problem
Java Developers of multi threaded application might feel a need to store global variables which should not be shared by multiple threads.
Example - Storing user information while handling a web request on multi threaded server.
Solution : ThreadLocal
ThreadLocal object acts as a variable container which enables you to create and maintain a global state which is tied to one thread. Each thread accessing the ThreadLocal
object will have it’s own copy of underlying variable.
ThreadLocal Example
In following example,
- Threads will create a random User Id at the start of their execution.
- Threads will ask
userIdContainer
to store their respective User id. - After random sleep threads will again access their User Id, and because
ThreadLocal
ties the state to each thread, threads will get their respective User Id.
As shown in below example, ThreadLocal
objects are generally used as static
and final
to keep the object globally accessible.
import java.util.Random;
public class ThreadLocalTest {
public static void main(String[] args) {
// Using Lambda to write Runnable implementation
Runnable r = () -> {
UserId.set("user" + new Random().nextInt(1000));
System.out.println(Thread.currentThread().getId()
+ ":" + UserId.get());
// Sleeping for random time
// to provide proof of overlapping statements by multiple threads
try { Thread.sleep(new Random().nextInt(500)); }
catch (InterruptedException e) {}
System.out.println(Thread.currentThread().getId()
+ ":" + UserId.get());
UserId.clear();
};
// Creating and starting 4 threads
new Thread(r).start();
new Thread(r).start();
new Thread(r).start();
new Thread(r).start();
}
}
class UserId {
private static final ThreadLocal<String> userIdContainer
= new ThreadLocal<>();
// Returns the current thread's User Id
public static String get() {
return userIdContainer.get();
}
// Sets current thread's User Id
public static void set(String userId) {
userIdContainer.set(userId);
}
// Remove value. when no longer required
public static void clear() {
userIdContainer.remove();
}
}
Output
10:user545
11:user591
12:user398
13:user149
11:user591
13:user149
12:user398
10:user545
Precautions while using ThreadLocal
- Do not forget to clean up the
ThreadLocal
object’s value usingremove()
method when value is no longer required in further execution. It may cause Out of Memory exceptions in your application. The same issue is discussed in the stackoverflow answer
ThreadLocal’s use in Spring MVC framework
In most multi-threaded web frameworks, ThreadLocal
is used internally to store HTTP request attributes throughout the life cycle of that request. One such example is org.springframework.web.context.request.RequestContextHolder
. Check out the source code on Github.
Conclusion
ThreadLocal
allows multi threaded Java program to manage Thread’s global state.