When and how should I use a ThreadLocal variable?
Solution 1
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);
}
}
Solution 2
Since a ThreadLocal
is a reference to data within a given Thread
, you can end up with classloading leaks when using ThreadLocal
s in application servers using thread pools. You need to be very careful about cleaning up any ThreadLocal
s you get()
or set()
by using the ThreadLocal
's remove()
method.
If you do not clean up when you're done, any references it holds to classes loaded as part of a deployed webapp will remain in the permanent heap and will never get garbage collected. Redeploying/undeploying the webapp will not clean up each Thread
's reference to your webapp's class(es) since the Thread
is not something owned by your webapp. Each successive deployment will create a new instance of the class which will never be garbage collected.
You will end up with out of memory exceptions due to java.lang.OutOfMemoryError: PermGen space
and after some googling will probably just increase -XX:MaxPermSize
instead of fixing the bug.
If you do end up experiencing these problems, you can determine which thread and class is retaining these references by using Eclipse's Memory Analyzer and/or by following Frank Kieviet's guide and followup.
Update: Re-discovered Alex Vasseur's blog entry that helped me track down some ThreadLocal
issues I was having.
Solution 3
Many frameworks use ThreadLocals to maintain some context related to the current thread. For example when the current transaction is stored in a ThreadLocal, you don't need to pass it as a parameter through every method call, in case someone down the stack needs access to it. Web applications might store information about the current request and session in a ThreadLocal, so that the application has easy access to them. With Guice you can use ThreadLocals when implementing custom scopes for the injected objects (Guice's default servlet scopes most probably use them as well).
ThreadLocals are one sort of global variables (although slightly less evil because they are restricted to one thread), so you should be careful when using them to avoid unwanted side-effects and memory leaks. Design your APIs so that the ThreadLocal values will always be automatically cleared when they are not needed anymore and that incorrect use of the API won't be possible (for example like this). ThreadLocals can be used to make the code cleaner, and in some rare cases they are the only way to make something work (my current project had two such cases; they are documented here under "Static Fields and Global Variables").
Solution 4
In Java, if you have a datum that can vary per-thread, your choices are to pass that datum around to every method that needs (or may need) it, or to associate the datum with the thread. Passing the datum around everywhere may be workable if all your methods already need to pass around a common "context" variable.
If that's not the case, you may not want to clutter up your method signatures with an additional parameter. In a non-threaded world, you could solve the problem with the Java equivalent of a global variable. In a threaded word, the equivalent of a global variable is a thread-local variable.
Solution 5
There is very good example in book 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. In the end he also explain how people can abuse it by using it as global variables.
I have copied the text from the mentioned book but code 3.10 is missing as it is not much important to understand where ThreadLocal should be use.
Thread-local variables are often used to prevent sharing in designs based on mutable Singletons or global variables. For example, a single-threaded application might maintain a global database connection that is initialized at startup to avoid having to pass a Connection to every method. Since JDBC connections may not be thread-safe, a multithreaded application that uses a global connection without additional coordination is not thread-safe either. By using a ThreadLocal to store the JDBC connection, as in ConnectionHolder in Listing 3.10, each thread will have its own connection.
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 easily implemented using a static Thread-Local holding the transaction context: when framework code needs to determine what transaction is currently running, it fetches the transaction context from this ThreadLocal. This is convenient in that it reduces the need to pass execution context information into every method, but couples any code that uses this mechanism to the framework.
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. Like global variables, thread-local variables can detract from reusability and introduce hidden couplings among classes, and should therefore be used with care.
Admin
Updated on July 24, 2022Comments
-
Admin over 1 year
When should I use a
ThreadLocal
variable?How is it used?
-
Julien Chastang almost 15 yearsAnother alternative to synchronization or threadlocal is to make the variable a local variable. Local vars are always thread safe. I assume that it is bad practice to make DateFormats local because they are expensive to create, but I have never seen solid metrics on this topic.
-
Ian Varley almost 14 yearsBy default, static objects, or objects explicitly passed between threads where both threads posses a reference to the same object, are shared. Objects declared locally in a thread are not shared (they're local to the thread's stack). Just wanted to clarify that.
-
Ray about 13 yearsdo you think this could be avoided by using a SoftReference?
-
yaKashif almost 12 yearsAlex Vasseur moved his blog. Here is a current link to the memory leak article.
-
Pankaj about 11 yearsHere is a complete example showing different threads have their own copy. journaldev.com/1076/…
-
Friedryk about 11 yearsI've just being hit the face with date/calendar/format concurrency problems. Though I understood quickly what was going on, your post made it plain and simple to solve my problems without major overhaul of my code. Thanks! Personnally I made a point in calling ThreadLocal remove after each get(), idealy in a finally clause. Any thoughts if it is overkill ? I wanted to make sure memory could be reclaimed after execution of enclosing Thread.
-
Volksman almost 11 yearsThat's exactly how the exPOJO framework (www.expojo.com) allows access to ORM Session/PersistenceManager without needing the overhead of annotations and injection. It is kind of like 'thread injection' instead of 'object injection'. It provides access to dependencies without the requirement (and overhead) of having them embedded in every object that might need those dependencies. It's amazing how 'light weight' you can make a DI framework when you use thread injection instead of classic DI (eg., Spring etc.,)
-
Donal Fellows almost 11 yearsThe thread that Julien links to has moved to here it seems, and is well worth reading…
-
Alexander Ryzhov almost 11 yearsThis is high price to pay for hacking
SimpleDateFormat
. Perhaps it's better to use a thread-safe alternative. If you agree that singletons are bad thenThreadLocal
is even worse. -
Ruan Mendes over 10 yearsSo you should avoid thread locals the same way you avoid globals. I cannot possibly accept that it's OK to create globals (thread locals) instead of passing values around, people don't like because it often reveals architecture problems that they don't want to fix.
-
supercat about 10 yearsRe-entrancy isn't a problem if code is prepared to deal with it. On entry, make note of whether the variable is already set, and on exit, restore its previous value (if there was any), or remove it (if not).
-
Xairoo almost 10 yearsThis is an awful lot of upvotes for an answer that, while informative, does not in any way actually answer the question.
-
Cornel Masson over 9 yearsPerhaps... It can be useful, though, if you have a huge, existing codebase to which you have to add a new datum that has to be passed around everywhere, e.g. a session context, db transaction, logged-in user, etc.
-
Jeremy Stein over 9 yearsWhy did I have to scroll down so far to find this essential answer!?
-
Sachin Gorade over 8 years@overthink Is there any reason to declare ThreadLocal static and final, I mean performance or something?
-
Renascienza over 8 years@SachinGorade is just to enforce just one formatter instance for each classloader. On environment that have just one main classloader, that works like a Singleton.
-
Renascienza over 8 yearsSingletons doesn't are "good" or "bad" on all situations. On a nutshell: The main objective of a Singleton is keep the creation of expensible objects at minimum, preferably only one. On multiple classloading environments (like web application containers) they are almost useless. They are hard to unit test or use on testing. Do you need a strategy to deal with.
-
tgkprog over 8 yearsOr just restart your node instead of a hot deploy. (for most cases, I'm sure there are others where you just need to wrap around a soft reference). But you see a big drop in objects used and time if you use thread locals or spring thread scope (reused across users as the thread pool for web requests is long living) instead of stuffing every service in a session scope.
-
Evil Washing Machine over 8 yearsNow that PermGen is killed by Java 8, does this change this answer in any way?
-
Didier A. almost 8 yearsIf the ThreadPool keeps the Threads alive, then their ThreadLocals will too, but they will be overwritten by the new values when the thread in the pool is allocated again no? Why would it leak? It just seems to me that you'd have a fix increase of memory maybe, equal to num thread * size of threadlocal value, but your ThreadPool should manage itself to a reasonable size, so this isn't really a memory leak, increasing MaxPermSize should in fact be a good solution.
-
Jayesh almost 8 years@IanVarley: Thanks for pointing that. So if we have variable that is declared and used in MyThread class, then do we need ThreadLocal in that case? Example: class MyThread extends Thread{ String var1;, int var2; } in this case var1 and var2 will be part of Thread own stack and is not shared, so do we require ThreadLocal in this case? I might be totally wrong in my understanding, please guide.
-
deep almost 8 yearsKudos for using datum instead of data.
-
sudeepdino008 almost 8 yearsIf each thread wants to have its own copy of something, why can't it simply be declared local( which is always thread safe)?
-
sudeepdino008 almost 8 yearsThe ThreadLocal.get() method will call ThreadLocal.initialValue() (once) for each thread, which means that a SimpleDateFormat object is created for each thread. Isn't it better then just to have SimpleDateFormat as local variables(since we don't have to deal with garbage collection issues) ?
-
Enerccio over 7 years@sudeepdino008 no because new SimpleDateFormat would have to be created each call to the method, which is silly
-
user1944408 over 7 yearsJust be careful not to use double brace initialization for your SimpleDateFormat because that would create an anonymous class so your class loader could not be garbage collected. memory leak: return new SimpleDateFormat(){{applyPattern("yyyyMMdd HHmm")}};
-
Konstantin Milyutin over 7 yearsI believe the answer is not relevant anymore, because
Thread
usesWeakReference<ThreadLocal>
. So when the associatedThreadLocal
isgc
'ed, the Map will also remove stale values during next rehashing. -
Saurabh Patil about 7 years@Robin: I disagree. The question is about how to use ThreadLocal correctly, to get a complete understanding of any concept (ThreadLocal here) it's also important to understand how not to use it and the risks of using it carelessly, and that is what Phil's answer is about. I'm glad he covered that point which isn't covered in any other answers. All those votes are well deserved. I believe SO should build understanding of concepts rather than just being a QA site.
-
Pacerier over 6 years@AlexanderRyzhov, A thread-safe alternative is an even higher price to pay since you need to pay synchronization overhead on every method call. Use a local variable instead.
-
Pacerier over 6 years@Enerccio, Dude, a member variable in the context of each object instance. It can be accessible from all method calls.
-
Pacerier over 6 years@Esko, In your project, your use of ThreadLocal in hashcode and equals is unneeded. A better approach is to create or pass a reference to a hashcode/equals function whenever it is needed. This way, you can completely avoid the need for ThreadLocal hack.
-
Pacerier over 6 years@JeremyStein, The better answers are at stackoverflow.com/a/817911/632951 and stackoverflow.com/a/17398338/632951 and stackoverflow.com/a/818364/632951
-
Pacerier over 6 years@Jeff, Dude, that's true of every code you write, not just
ThreadLocal
pattern. If you doF(){ member=random(); F2(); write(member); }
and F2 overrides member with a new value, then obviouslywrite(member)
will no longer write the number you haverandom()
ed. This is literally just common sense. Similarly, if you doF(){ F(); }
, then gd luck with your infinite loop! This is true everywhere and is not specific toThreadLocal
. -
Enerccio over 6 years@Pacerier how is member variable related? He was talking about local variable, which means every method call, new
SimpleDateFormat
would be created, which is a waste. Thread local is much better because it is flexible and memory "leak" is hardly noticeable and can be managed when thread is destroyed anyways. Member variableSimpleDateFormat
is bad because it is not thread safe! -
Enerccio over 6 years@Pacerier why would you need any synchronization with
ThreadLocal
? -
Enerccio over 6 yearsThreadLocals are NOT global state unless you make it global state. They are practically always accessible stack resource. You can simulate thread local with simply passing that variable in all your methods (which is retarded); that doesn't make it global state...
-
Dimos over 6 yearsIt is a form of global state, in the sense that it's accessible from anywhere in the code (in the same thread's context). This comes with all the repercussions, such as not being able to reason about who reads and writes this value. Using a function parameter is not a retarded thing, it's a good practice promoting clean interfaces. However, I agree with you that passing a parameter across the whole depth of your codebase is a code smell. But, I also believe that in many occasions the use of ThreadLocal is a code smell in the first place which led you here, so this what one should reconsider.
-
Enerccio over 6 yearsIt can simply be a part of object state, doesn't have to be used globally. Sure, you get little bit overhead, but if multiple objects have to have different state per thread, you can use
ThreadLocal
as object field... -
Dimos over 6 yearsYou're right. I've probably stumbled upon several misuses of
ThreadLocal
, where it was accessible globally. As you said, it can still be used as a class field limiting the visibility. -
Rick-Rainer Ludwig about 6 yearsIn this example is a major issue: Who is responsible for the closing the connection? Instead of creating this connection as initiali value, let the consumer of the connection create the connection explicitly and bind it to the thread via ThreadLocal. The creator of the connection is then also responsbible for closing. This is not clear in this example. Creating and binding the connection can also be hidden in a simple framework by something like Transaction.begin() and Transaction.end().
-
Dexter about 6 yearsThis is the best explanation of the use of TL.
-
JMess almost 6 years@sudeepdino008 you don't always have control of the creation of those threads (webapp frameworks, threadpool libraries)
-
dashenswen almost 5 yearsI still didn't see the benefit of using ThreadLocal to generate the unique id in example one if all your purpose is to return an incremental unique integer value. ``` public class ThreadId { // Atomic integer containing the next thread ID to be assigned private static final AtomicInteger nextId = new AtomicInteger(0); // Returns the current thread's unique ID, assigning it if necessary public static int get() { return nextId..getAndIncrement(); } } ```
-
prnjn almost 5 years@Robin answer doesn't have to be exactly what the other person said, if something is already said then additional information is more valuable than writing the same thing over again. And here the answer holds quality and important information.
-
Vasif over 4 yearsbut this solution has own problem like your objects are still exist on ThreadPool and it can cause OOM issue if you are going to store different objects in ThreadLocal and your application get a lot of requests. I saw it as a solution for passing object to other methods without passing it as a parameter. So u can pu object in ThreadLocal and then remove it in finally to clear it up.
-
Siddhartha almost 4 yearsThis made me curious.
'datum' is the singular form and 'data' is the plural form.
-
CodesInTheDark over 2 years@KonstantinMilyutin The problem is that Thread does not use WeakReference for values, only for the keys. If a value uses a custom class it will prevent its ClassLoader to be gc-ed and in turn, it will prevent the whole application and its ThreadLocals to be gc-ed because you get a circular reference.