What is ThreadLocal?
In Java, ThreadLocal has been used since JDK 1.2. In multi-threaded programming, there are multiple ways to achieve thread safety via synchronization / locks. ThreadLocal is a different way to achieve thread-safety by providing explicitly a copy of Object to each thread. Since the Object is not shared, there is no requirement of Synchronization. Therefore, it will help the application performance & system scalability improvement.
In a word, ThreadLocal can be associated with Thread scope, all the code which is executed by Thread has access to ThreadLocal variables but two threads can not see other ThreadLocal variables.
When to use ThreadLocal?
When you need a variable’s value to depend on the current thread and it isn’t convenient to attach the value to the thread in other ways, you can consider using ThreadLocal.
- If the variable is not thread safe, it can become thread safe by saving it into ThreadLocal.
For example: Hibernate Session is not thread safe, and can be save into the ThreadLocal. In this case, only the thread owning the Session can access the session object saved in ThreadLocal. - Implement per thread context information like transaction ID
What we should pay attention to?
Since a ThreadLocal is a reference to data within a given Thread, there is a possibility of memory leaks when using ThreadLocals in application servers which use thread pools. Therefore, make sure the thread clean any ThreadLocal variables before exit. ThreadLocal’s remove() and set(null) methods can be used.
If a ThreadLocal variable is not cleaned up before being destroyed, any references it holds to classes loaded as part of a deployed web application will remain in the permanent heap, and will not get garbage collected. Redeploying/undeploying the webapp will not clean up each Thread’s reference the object class since the Thread is not something owned by the new webapp anymore. This will lead to memory leakage and finally java.lang.OutOfMemoryError in the future.
How to use ThreadLocal?
1. Create a ThreadLocal variable
A ThreadLocal variable is generally private static field in Classes and maintain its state inside Thread.
1 |
private static final ThreadLocal<Session> threadLocal = new ThreadLocal<Session>(); |
2. To put Object into ThreadLocal
1 |
threadLocal.set(session); |
3. Get Object form ThreadLocal
1 |
Session session = (Session) threadLocal.get(); |
4. Remove object from ThreadLocal
1 |
threadLocal.set(null); |
or
1 |
threadLocal.remove(); |
Example:
User context to be saved in ThreadLocal
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
package net.tecbar.threadlocal; public class UserContext { private String contextId; public UserContext(String contextId) { this.contextId = contextId; } public String getContextId() { return contextId; } public void setContextId(String contextId) { this.contextId = contextId; } @Override public String toString() { return "UserContext [contextId=" + contextId + "]"; } } |
Demo client
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
package net.tecbar.threadlocal; public class ContextThreadDemo implements Runnable { private static final ThreadLocal<UserContext> local = new ThreadLocal<UserContext>(); public ContextThreadDemo() { } public static void main(String[] args) { Thread thread1 = new Thread(new ContextThreadDemo()); Thread thread2 = new Thread(new ContextThreadDemo()); Thread thread3 = new Thread(new ContextThreadDemo()); thread1.start(); thread2.start(); thread3.start(); } @Override public void run() { saveContext(); getAndRemoveContext(); } public void saveContext() { UserContext ctx = new UserContext(Thread.currentThread().getName()); local.set(ctx); // each thread saves a context to the shared ThreadLocal System.out.println("save to thread name: " + Thread.currentThread().getName()); } public void getAndRemoveContext() { UserContext ctx2 = local.get(); // each thread gets its own copy System.out.println(Thread.currentThread().getName() + " context string: " + ctx2); local.remove(); } } |
Output:
save to thread name: Thread-2
save to thread name: Thread-1
Thread-1 context string: UserContext [contextId=Thread-1]
save to thread name: Thread-0
Thread-0 context string: UserContext [contextId=Thread-0]
Thread-2 context string: UserContext [contextId=Thread-2]
Your post is very nice and easily understandable
I have a doubt from your post – “In the example you are explicitly running 3 threads through the run() method with same object. But in real time application, we don’t use explicit threads to run our application. There might be many threads which run to complete a single user request. That means each thread might have some data to be updated to the user session data. But in your example, which ever thread that creates the thread local object has the access to the session object, and only that thread can modify the session data. So what about all other threads that participate to complete the user request. They wont get access to modify the session object..? So how are we resolving this issue.