When and how should I use a ThreadLocal variable?

352,658

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);
    }
}

Documentation.

Solution 2

Since a ThreadLocal is a reference to data within a given Thread, you can end up with classloading leaks when using ThreadLocals in application servers using thread pools. You need to be very careful about cleaning up any ThreadLocals 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.

Share:
352,658
Admin
Author by

Admin

Updated on July 24, 2022

Comments

  • Admin
    Admin over 1 year

    When should I use a ThreadLocal variable?

    How is it used?

  • Julien Chastang
    Julien Chastang almost 15 years
    Another 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
    Ian Varley almost 14 years
    By 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
    Ray about 13 years
    do you think this could be avoided by using a SoftReference?
  • yaKashif
    yaKashif almost 12 years
    Alex Vasseur moved his blog. Here is a current link to the memory leak article.
  • Pankaj
    Pankaj about 11 years
    Here is a complete example showing different threads have their own copy. journaldev.com/1076/…
  • Friedryk
    Friedryk about 11 years
    I'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
    Volksman almost 11 years
    That'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
    Donal Fellows almost 11 years
    The thread that Julien links to has moved to here it seems, and is well worth reading…
  • Alexander Ryzhov
    Alexander Ryzhov almost 11 years
    This 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 then ThreadLocal is even worse.
  • Ruan Mendes
    Ruan Mendes over 10 years
    So 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
    supercat about 10 years
    Re-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
    Xairoo almost 10 years
    This is an awful lot of upvotes for an answer that, while informative, does not in any way actually answer the question.
  • Cornel Masson
    Cornel Masson over 9 years
    Perhaps... 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
    Jeremy Stein over 9 years
    Why did I have to scroll down so far to find this essential answer!?
  • Sachin Gorade
    Sachin Gorade over 8 years
    @overthink Is there any reason to declare ThreadLocal static and final, I mean performance or something?
  • Renascienza
    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
    Renascienza over 8 years
    Singletons 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
    tgkprog over 8 years
    Or 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
    Evil Washing Machine over 8 years
    Now that PermGen is killed by Java 8, does this change this answer in any way?
  • Didier A.
    Didier A. almost 8 years
    If 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
    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
    deep almost 8 years
    Kudos for using datum instead of data.
  • sudeepdino008
    sudeepdino008 almost 8 years
    If each thread wants to have its own copy of something, why can't it simply be declared local( which is always thread safe)?
  • sudeepdino008
    sudeepdino008 almost 8 years
    The 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
    Enerccio over 7 years
    @sudeepdino008 no because new SimpleDateFormat would have to be created each call to the method, which is silly
  • user1944408
    user1944408 over 7 years
    Just 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
    Konstantin Milyutin over 7 years
    I believe the answer is not relevant anymore, because Thread uses WeakReference<ThreadLocal>. So when the associated ThreadLocal is gc'ed, the Map will also remove stale values during next rehashing.
  • Saurabh Patil
    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
    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
    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
    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
    Pacerier over 6 years
  • Pacerier
    Pacerier over 6 years
    @Jeff, Dude, that's true of every code you write, not just ThreadLocal pattern. If you do F(){ member=random(); F2(); write(member); } and F2 overrides member with a new value, then obviously write(member) will no longer write the number you have random()ed. This is literally just common sense. Similarly, if you do F(){ F(); }, then gd luck with your infinite loop! This is true everywhere and is not specific to ThreadLocal.
  • Enerccio
    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 variable SimpleDateFormat is bad because it is not thread safe!
  • Enerccio
    Enerccio over 6 years
    @Pacerier why would you need any synchronization with ThreadLocal?
  • Enerccio
    Enerccio over 6 years
    ThreadLocals 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
    Dimos over 6 years
    It 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
    Enerccio over 6 years
    It 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
    Dimos over 6 years
    You'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
    Rick-Rainer Ludwig about 6 years
    In 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
    Dexter about 6 years
    This is the best explanation of the use of TL.
  • JMess
    JMess almost 6 years
    @sudeepdino008 you don't always have control of the creation of those threads (webapp frameworks, threadpool libraries)
  • dashenswen
    dashenswen almost 5 years
    I 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
    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
    Vasif over 4 years
    but 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
    Siddhartha almost 4 years
    This made me curious. 'datum' is the singular form and 'data' is the plural form.
  • CodesInTheDark
    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.