When and How to Use a Threadlocal Variable

When and how should I use a ThreadLocal variable?

One possible (and common) use is when you have some object that is not thread-safe, but you want to avoid synchronizing access to that object (I'm looking at you, SimpleDateFormat). Instead, give each thread its own instance of the object.

For example:

public class Foo
{
// SimpleDateFormat is not thread-safe, so give one to each thread
private static final ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>(){
@Override
protected SimpleDateFormat initialValue()
{
return new SimpleDateFormat("yyyyMMdd HHmm");
}
};

public String formatIt(Date date)
{
return formatter.get().format(date);
}
}

Documentation.

When is ThreadLocal preferred over Local Variables?

ThreadLocal is is not an alternative to local variables. You use ThreadLocal for data that have to be static, but which must not be shared between threads.

static final ThreadLocal<MyFoo> myFoo =
ThreadLocal.withInitial(() -> new MyFoo());

If you have a ThreadLocal variable that is not static, then you're either doing something that's overly complicated, or you're doing something that's just plain wrong.

On the other hand, if you have any variable that is static (whether it is ThreadLocal or not), then you should be aware that that's a design choice that will limit your ability to test and grow the program.

An example that shows the requirement of ThreadLocal usage

Behind the Scenes, when a ThreadLocal Object is created, it actually creates a HashMap internally, something like below :

 HashMap<ThreadID,Value> map;

so when a particular Thread add a value to Thread Local object it will insert the current thread's ThreadId as "key" and the Value as "value" in the HashMap.

 map.put(thread.currentthread().getid() , Value );

so again when we fetch the value from the Thread Local object, it will do the below operation :

map.get(thread.currentthread().getid());

so even thought we create ONLY one instance of ThreadLOcal object, but we will be able to make them local to each Thread .

Please check the below piece of code.

we are creating 3 threads by passing the runnable object to it and also we are setting the name of each thread in the constructor itself.

In thr run() method we are setting the ThreadName into the Thread Local object and the thread is put into sleep(), Meanwhile, other thread can enter the run() method and again set its thraedName to the SAME thread Local instance.

Once the Thread is awake, we are fetching the data back from the Thread Local object and printing it...

public class ThreadLocalDemo {

public static void main(String[] args) {
testLocal oneInstance = new testLocal();

Thread A = new Thread(oneInstance);
Thread B = new Thread(oneInstance);
Thread C = new Thread(oneInstance);

A.start();
try
{
Thread.sleep(400);
}
catch(InterruptedException e){}

B.start();
try
{
Thread.sleep(400);
}
catch(InterruptedException e){}

C.start();
try
{
Thread.sleep(400);
}
catch(InterruptedException e){}
}

}

class testLocal implements Runnable
{
private static final ThreadLocal local = new ThreadLocal<String>(){
@Override
protected String initialValue() {
System.out.println(" local thread initialValue() called ");
return "intial Value";
}
};

@Override
public void run() {
local.set(Thread.currentThread().getName());
try
{
Thread.sleep(2000);
}
catch(InterruptedException e){}
System.out.print(Thread.currentThread().getName() + " run() " );
System.out.print(" called.... ");
System.out.println(local.get());
}

}

Purpose of ThreadLocal?

A thread is a unit of execution and so multiple thread can execute the same code at the same time. If multiple threads execute on an object/instance at the same time they will share the instance variables. Each thread will have its own local variables but it is difficult to share these across objects without passing parameters.

It is best explained by way of an example. Say you have a Servlet that gets the logged in user and then executes some code.

doGet(HttpServletRequest req, HttpServletResponse resp) {
User user = getLoggedInUser(req);
doSomething()
doSomethingElse()
renderResponse(resp)
}

Now what happens if the doSomething() methods needs access to the user object? You can't make the user object an instance or static variable because each thread will then use the same user object. You could pass the user object around as a parameter but this quickly becomes messy and leaks user objects into every method call:

doGet(HttpServletRequest req, HttpServletResponse resp) {
User user = getLoggedInUser(req);
doSomething(user)
doSomethingElse(user)
renderResponse(resp,user)
}

A more elegant solution is to put the user object into a 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 the user object at any time can get hold of it by extracting it from the thread local, without needing to resort to those pesky extra parameters:

User user = StaticClass.getThreadLocal().get()

If you use this approach be mindful to remove the objects again in a finally block. Otherwise the user object might hang around in environments that use a Thread Pool (like Tomcat app server).

Edit: The code for static class

class StaticClass {
static private ThreadLocal<User> threadLocal = new ThreadLocal<>();

static ThreadLocal<User> getThreadLocal() {
return threadLocal;
}
}

What is the use of ThreadLocal?

A thread doesn't have to keep variables in its local cache -- it's just that it's allowed to, unless you tell it otherwise.

So:

  • If you want to force a thread to share its state with other threads, you have to use synchronization of some sort (including synchronized blocks, volatile variables, etc).
  • If you want to prevent a thread from sharing its state with other threads, you have to use ThreadLocal (assuming the object that holds the variable is known to multiple threads -- if it's not, then everything is thread-local anyway!).

What is the best way to use ThreadLocal - through static or non-static methods?

Despite what others may say, ThreadLocal variables aren't inherently evil, they just require a little extra care and understanding when using. Thread safety isn't really relevant as they are inherently tied to one thread. The concern comes in when those threads may be reused by other, disparate users of an application. In Java based web apps, this is the case; HOWEVER, you can count on only one user/request living on that thread at one time. The extremely important step is to ensure you clean up your ThreadLocal objects at the end of each request.

Therefore, to avoid having to unnecessarily instantiate a new context for every request, I would recommend creating multiple static type-safe ThreadLocal objects, all living in a "context" class where these objects are related in some way. You can use multiple context classes to organize various groups of these contextual items.

However, in the spirit of ThreadLocal critics, I would agree that ThreadLocals should be used somewhat sparingly and overuse can potentially be a code smell.

Following is an example of the aforementioned approach.

The "context" class.

public class LogContext {

private static ThreadLocal<String> localCorrelationId = new ThreadLocal<String>();
private static ThreadLocal<String> localUserId = new ThreadLocal<String>();

public static String getCorrelationId() {
return localCorrelationId.get();
}

public static void setCorrelationId(String correlationId) {
localCorrelationId.set(correlationId);
}

public static String getUserId() {
return localUserId.get();
}

public static void setUserId(String userId) {
localUserId.set(userId);
}

public static void cleanup() {
localCorrelationId.remove();
localUserId.remove();
}
}

Managing the context via a Servlet Filter

@WebFilter(filterName = "LogContextFilter", urlPatterns = {"/*"})
public class LogContextFilter implements Filter {

public void init(FilterConfig filterConfig) {

}

public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {

try {
LogContext.setCorrelationId(UUID.randomUUID().toString());
chain.doFilter(request, response);
} catch (Throwable t) {
t.printStackTrace();
} finally {
//This is critical!
LogContext.cleanup();
}

}

public void destroy() {

}

}

Accessing the context (e.g. from a Servlet)

@WebServlet(name = "SimpleServlet", urlPatterns = {"/SimpleServlet"})
public class SimpleServlet extends HttpServlet {

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

String correlationId = LogContext.getCorrelationId();
}

}

Using ThreadLocal in instance variables

Do Java ThreadLocal variables produce thread-local values if they are used as instance variables.

Yes, they do. Think about it: Not the ThreadLocal is static or non-static, only the reference to the ThreadLocal is static or not. The object itself looks always the same.

Does any of the above approaches make sense for the case described, or should the ThreadLocal declarations be static?

Not really.

Example:

[DateFormat] format = new ThreadLocal<DateFormat>()
{...}.get();
formats.put(pattern, format);

means, that you always create a new ThreadLocal, call get immediately and put the result (not the ThreadLocal) into a map. This means you neither reuse the ThreadLocal nor the format itself.

so, as far as I understand your usecase you might want something like this:

public class XXX {
private final static Map<String, SimpleDateFormatThreadLocal> formatMap =
new HashMap<String, SimpleDateFormatThreadLocal>();

static {
String[] patterns = {"a", "b", "c"};
for(String pattern: patterns){
formatMap.put(pattern, new SimpleDateFormatThreadLocal(pattern));
}
}

private static class SimpleDateFormatThreadLocal extends ThreadLocal<SimpleDateFormat> {
private final String pattern;

public SimpleDateFormatThreadLocal(String pattern) {
this.pattern = pattern;
}
@Override
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat(pattern);
}
}
}

Example usage would be like this:

public void run(){
String s = formatMap.get("a").get().format(new Date());
System.out.println(s);
}

Here you

  • reuse the ThreadLocal objects
  • reuse the DateFormat objects (per thread of course)
  • avoid creating DateFormats which are not used in some threads.

How threadlocal variable is different from a method level variable

First question: each thread updates its copy of threadlocal variable, no global state is shared between threads.

Second question: if you declare local variable it behaves similary to threadlocal - every thread has its own copy but you don't have global access to it e.g. in another method - that's when threadlocal is useful.

ThreadLocal Concept: Doesn't any variable within run() or call() a thread local?

Local variables within a method are always local to the thread, as they live on the stack. However, instance variables of the class implementing the thread live on the heap and are shared by all threads.

If each thread needs its own copy you need to use ThreadLocal, which under the covers is just a Map<key-class,value-class> where the key is the thread identifier and the value is the thread-local value itself.

Consider a single instance of a class that can be used by multiple threads. Note, I'm NOT referring to the Runnable itself, but to an instance whose methods can be invoked from several different threads. There is a single instance and the class is designed to be used by multiple threads in parallel. So it needs to keep each calling thread's state separate from other threads' state. This is the use case for ThreadLocal.



Related Topics



Leave a reply



Submit