ChatGPT解决这个技术问题 Extra ChatGPT

When and how should I use a ThreadLocal variable?

When should I use a ThreadLocal variable?

How is it used?

If you are using ThreadLocal, never write a wrapper over it !!! Each and every developer who wants to use the variable must know it is 'ThreadLocal'
@Notabug If you are explicit, you can name your variable so that it's it that you're dealing with a ThreadLocal value, e.g. RequestUtils.getCurrentRequestThreadLocal(). Not saying this is very elegant though, but this stems from the fact that ThreadLocal itself is not very elegant in most cases.

o
overthink

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.


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.
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.
@overthink Is there any reason to declare ThreadLocal static and final, I mean performance or something?
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) ?
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")}};
L
Laurel

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.


Alex Vasseur moved his blog. Here is a current link to the memory leak article.
The thread that Julien links to has moved to here it seems, and is well worth reading…
This is an awful lot of upvotes for an answer that, while informative, does not in any way actually answer the question.
Now that PermGen is killed by Java 8, does this change this answer in any way?
@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.
L
Laurel

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").


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.,)
Why did I have to scroll down so far to find this essential answer!?
@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.
This is the best explanation of the use of TL.
u
user100464

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.


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.
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.
Kudos for using datum instead of data.
This made me curious. 'datum' is the singular form and 'data' is the plural form.
C
Community

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.


L
Laurel

Essentially, when you need a variable's value to depend on the current thread and it isn't convenient for you to attach the value to the thread in some other way (for example, subclassing thread).

A typical case is where some other framework has created the thread that your code is running in, e.g. a servlet container, or where it just makes more sense to use ThreadLocal because your variable is then "in its logical place" (rather than a variable hanging from a Thread subclass or in some other hash map).

On my web site, I have some further discussion and examples of when to use ThreadLocal that may also be of interest.

Some people advocate using ThreadLocal as a way to attach a "thread ID" to each thread in certain concurrent algorithms where you need a thread number (see e.g. Herlihy & Shavit). In such cases, check that you're really getting a benefit!


L
Laurel

ThreadLocal in Java had been introduced on JDK 1.2 but was later generified in JDK 1.5 to introduce type safety on ThreadLocal variable. ThreadLocal can be associated with Thread scope, all the code which is executed by Thread has access to ThreadLocal variables but two thread can not see each others ThreadLocal variable. Each thread holds an exclusive copy of ThreadLocal variable which becomes eligible to Garbage collection after thread finished or died, normally or due to any Exception, Given those ThreadLocal variable doesn't have any other live references. ThreadLocal variables in Java are generally private static fields in Classes and maintain its state inside Thread.

Read more: ThreadLocal in Java - Example Program and Tutorial


l
lakshman

The documentation says it very well: "each thread that accesses [a thread-local variable] (via its get or set method) has its own, independently initialized copy of the variable".

You use one when each thread must have its own copy of something. By default, data is shared between threads.


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.
@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.
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 you don't always have control of the creation of those threads (webapp frameworks, threadpool libraries)
L
L Joey

Webapp server may keep a thread pool, and a ThreadLocal var should be removed before response to the client, thus current thread may be reused by next request.


B
Brad Larson

Two use cases where threadlocal variable can be used - 1- When we have a requirement to associate state with a thread (e.g., a user ID or Transaction ID). That usually happens with a web application that every request going to a servlet has a unique transactionID associated with it.

// This class will provide a thread local variable which
// will provide a unique ID for each thread
class ThreadId {
    // Atomic integer containing the next thread ID to be assigned
    private static final AtomicInteger nextId = new AtomicInteger(0);

    // Thread local variable containing each thread's ID
    private static final ThreadLocal<Integer> threadId =
        ThreadLocal.<Integer>withInitial(()-> {return nextId.getAndIncrement();});

    // Returns the current thread's unique ID, assigning it if necessary
    public static int get() {
        return threadId.get();
    }
}

Note that here the method withInitial is implemented using lambda expression. 2- Another use case is when we want to have a thread safe instance and we don't want to use synchronization as the performance cost with synchronization is more. One such case is when SimpleDateFormat is used. Since SimpleDateFormat is not thread safe so we have to provide mechanism to make it thread safe.

public class ThreadLocalDemo1 implements Runnable {
    // threadlocal variable is created
    private static final ThreadLocal<SimpleDateFormat> dateFormat = new ThreadLocal<SimpleDateFormat>(){
        @Override
        protected SimpleDateFormat initialValue(){
            System.out.println("Initializing SimpleDateFormat for - " + Thread.currentThread().getName() );
            return new SimpleDateFormat("dd/MM/yyyy");
        }
    };

    public static void main(String[] args) {
        ThreadLocalDemo1 td = new ThreadLocalDemo1();
        // Two threads are created
        Thread t1 = new Thread(td, "Thread-1");
        Thread t2 = new Thread(td, "Thread-2");
        t1.start();
        t2.start();
    }

    @Override
    public void run() {
        System.out.println("Thread run execution started for " + Thread.currentThread().getName());
        System.out.println("Date formatter pattern is  " + dateFormat.get().toPattern());
        System.out.println("Formatted date is " + dateFormat.get().format(new Date()));
    } 

}

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(); } } ```
A
Andrii Abramov

Since Java 8 release, there is more declarative way to initialize ThreadLocal:

ThreadLocal<Cipher> local = ThreadLocal.withInitial(() -> "init value");

Until Java 8 release you had to do the following:

ThreadLocal<String> local = new ThreadLocal<String>(){
    @Override
    protected String initialValue() {
        return "init value";
    }
};

Moreover, if instantiation method (constructor, factory method) of class that is used for ThreadLocal does not take any parameters, you can simply use method references (introduced in Java 8):

class NotThreadSafe {
    // no parameters
    public NotThreadSafe(){}
}

ThreadLocal<NotThreadSafe> container = ThreadLocal.withInitial(NotThreadSafe::new);

Note: Evaluation is lazy since you are passing java.util.function.Supplier lambda that is evaluated only when ThreadLocal#get is called but value was not previously evaluated.


J
Jeff Richley

You have to be very careful with the ThreadLocal pattern. There are some major down sides like Phil mentioned, but one that wasn't mentioned is to make sure that the code that sets up the ThreadLocal context isn't "re-entrant."

Bad things can happen when the code that sets the information gets run a second or third time because information on your thread can start to mutate when you didn't expect it. So take care to make sure the ThreadLocal information hasn't been set before you set it again.


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).
@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.
K
Kanagavelu Sugumar

ThreadLocal will ensure accessing the mutable object by the multiple threads in the non synchronized method is synchronized, means making the mutable object to be immutable within the method. This is achieved by giving new instance of mutable object for each thread try accessing it. So It is local copy to the each thread. This is some hack on making instance variable in a method to be accessed like a local variable. As you aware method local variable is only available to the thread, one difference is; method local variables will not available to the thread once method execution is over where as mutable object shared with threadlocal will be available across multiple methods till we clean it up.

By Definition:

The ThreadLocal class in Java enables you to create variables that can only be read and written by the same thread. Thus, even if two threads are executing the same code, and the code has a reference to a ThreadLocal variable, then the two threads cannot see each other's ThreadLocal variables.

Each Thread in java contains ThreadLocalMap in it.
Where

Key = One ThreadLocal object shared across threads.
value = Mutable object which has to be used synchronously, this will be instantiated for each thread.

Achieving the ThreadLocal:

Now create a wrapper class for ThreadLocal which is going to hold the mutable object like below (with or without initialValue()).
Now getter and setter of this wrapper will work on threadlocal instance instead of mutable object.

If getter() of threadlocal didn't find any value with in the threadlocalmap of the Thread; then it will invoke the initialValue() to get its private copy with respect to the thread.

class SimpleDateFormatInstancePerThread {

    private static final ThreadLocal<SimpleDateFormat> dateFormatHolder = new ThreadLocal<SimpleDateFormat>() {

        @Override
        protected SimpleDateFormat initialValue() {
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd") {
                UUID id = UUID.randomUUID();
                @Override
                public String toString() {
                    return id.toString();
                };
            };
            System.out.println("Creating SimpleDateFormat instance " + dateFormat +" for Thread : " + Thread.currentThread().getName());
            return dateFormat;
        }
    };

    /*
     * Every time there is a call for DateFormat, ThreadLocal will return calling
     * Thread's copy of SimpleDateFormat
     */
    public static DateFormat getDateFormatter() {
        return dateFormatHolder.get();
    }

    public static void cleanup() {
        dateFormatHolder.remove();
    }
}

Now wrapper.getDateFormatter() will call threadlocal.get() and that will check the currentThread.threadLocalMap contains this (threadlocal) instance.
If yes return the value (SimpleDateFormat) for corresponding threadlocal instance
else add the map with this threadlocal instance, initialValue().

Herewith thread safety achieved on this mutable class; by each thread is working with its own mutable instance but with same ThreadLocal instance. Means All the thread will share the same ThreadLocal instance as key, but different SimpleDateFormat instance as value.

https://github.com/skanagavelu/yt.tech/blob/master/src/ThreadLocalTest.java


L
Limestone

when?

When an object is not thread-safe, instead of synchronization which hampers the scalability, give one object to every thread and keep it thread scope, which is ThreadLocal. One of most often used but not thread-safe objects are database Connection and JMSConnection.

How ?

One example is Spring framework uses ThreadLocal heavily for managing transactions behind the scenes by keeping these connection objects in ThreadLocal variables. At high level, when a transaction is started it gets the connection ( and disables the auto commit ) and keeps it in ThreadLocal. on further db calls it uses same connection to communicate with db. At the end, it takes the connection from ThreadLocal and commits ( or rollback ) the transaction and releases the connection.

I think log4j also uses ThreadLocal for maintaining MDC.


D
Dimos

ThreadLocal is useful, when you want to have some state that should not be shared amongst different threads, but it should be accessible from each thread during its whole lifetime.

As an example, imagine a web application, where each request is served by a different thread. Imagine that for each request you need a piece of data multiple times, which is quite expensive to compute. However, that data might have changed for each incoming request, which means that you can't use a plain cache. A simple, quick solution to this problem would be to have a ThreadLocal variable holding access to this data, so that you have to calculate it only once for each request. Of course, this problem can also be solved without the use of ThreadLocal, but I devised it for illustration purposes.

That said, have in mind that ThreadLocals are essentially a form of global state. As a result, it has many other implications and should be used only after considering all the other possible solutions.


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...
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.
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...
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.
m
mohsen.nour

There are 3 scenarios for using a class helper like SimpleDateFormat in multithread code, which best one is use ThreadLocal

Scenarios

1- Using like share object by the help of lock or synchronization mechanism which makes the app slow

Thread pool Scenarios

2- Using as a local object inside a method

In thread pool, in this scenario, if we have 4 thread each one has 1000 task time then we have 4000 SimpleDateFormat object created and waiting for GC to erase them

3- Using ThreadLocal

In thread pool, if we have 4 thread and we gave to each thread one SimpleDateFormat instance so we have 4 threads, 4 objects of SimpleDateFormat.

There is no need of lock mechanism and object creation and destruction. (Good time complexity and space complexity)

https://www.youtube.com/watch?v=sjMe9aecW_A


C
Colselaw

Nothing really new here, but I discovered today that ThreadLocal is very useful when using Bean Validation in a web application. Validation messages are localized, but by default use Locale.getDefault(). You can configure the Validator with a different MessageInterpolator, but there's no way to specify the Locale when you call validate. So you could create a static ThreadLocal<Locale> (or better yet, a general container with other things you might need to be ThreadLocal and then have your custom MessageInterpolator pick the Locale from that. Next step is to write a ServletFilter which uses a session value or request.getLocale() to pick the locale and store it in your ThreadLocal reference.


A
Arjan Tijms

As was mentioned by @unknown (google), it's usage is to define a global variable in which the value referenced can be unique in each thread. It's usages typically entails storing some sort of contextual information that is linked to the current thread of execution.

We use it in a Java EE environment to pass user identity to classes that are not Java EE aware (don't have access to HttpSession, or the EJB SessionContext). This way the code, which makes usage of identity for security based operations, can access the identity from anywhere, without having to explicitly pass it in every method call.

The request/response cycle of operations in most Java EE calls makes this type of usage easy since it gives well defined entry and exit points to set and unset the ThreadLocal.


b
bpjoshi

Thread-local variables are often used to prevent sharing in designs based on mutable Singletons or global variables.

It can be used in scenarios like making seperate JDBC connection for each thread when you are not using a Connection Pool.

private static ThreadLocal<Connection> connectionHolder
           = new ThreadLocal<Connection>() {
      public Connection initialValue() {
           return DriverManager.getConnection(DB_URL);
          }
     };

public static Connection getConnection() {
      return connectionHolder.get();
} 

When you call getConnection, it will return a connection associated with that thread.The same can be done with other properties like dateformat, transaction context that you don't want to share between threads.

You could have also used local variables for the same, but these resource usually take up time in creation,so you don't want to create them again and again whenever you perform some business logic with them. However, ThreadLocal values are stored in the thread object itself and as soon as the thread is garbage collected, these values are gone too.

This link explains use of ThreadLocal very well.


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().
I
Ian Ringrose

Caching, sometime you have to calculate the same value lots of time so by storing the last set of inputs to a method and the result you can speed the code up. By using Thread Local Storage you avoid having to think about locking.


A
Ajay Kumar

ThreadLocal is a specially provisioned functionality by JVM to provide an isolated storage space for threads only. like the value of instance scoped variable are bound to a given instance of a class only. each object has its only values and they can not see each other value. so is the concept of ThreadLocal variables, they are local to the thread in the sense of object instances other thread except for the one which created it, can not see it. See Here

import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;


public class ThreadId {
private static final AtomicInteger nextId = new AtomicInteger(1000);

// Thread local variable containing each thread's ID
private static final ThreadLocal<Integer> threadId = ThreadLocal.withInitial(() -> nextId.getAndIncrement());


// Returns the current thread's unique ID, assigning it if necessary
public static int get() {
    return threadId.get();
}

public static void main(String[] args) {

    new Thread(() -> IntStream.range(1, 3).forEach(i -> {
        System.out.println(Thread.currentThread().getName() + " >> " + new ThreadId().get());
    })).start();

    new Thread(() -> IntStream.range(1, 3).forEach(i -> {
        System.out.println(Thread.currentThread().getName() + " >> " + new ThreadId().get());
    })).start();

    new Thread(() -> IntStream.range(1, 3).forEach(i -> {
        System.out.println(Thread.currentThread().getName() + " >> " + new ThreadId().get());
    })).start();

}
}

P
Pritesh Patel

The ThreadLocal class in Java enables you to create variables that can only be read and written by the same thread. Thus, even if two threads are executing the same code, and the code has a reference to a ThreadLocal variable, then the two threads cannot see each other's ThreadLocal variables.

Read more


Y
Young

[For Reference]ThreadLocal cannot solve update problems of shared object. It is recommended to use a staticThreadLocal object which is shared by all operations in the same thread. [Mandatory]remove() method must be implemented by ThreadLocal variables, especially when using thread pools in which threads are often reused. Otherwise, it may affect subsequent business logic and cause unexpected problems such as memory leak.


D
Dev Amitabh

Threadlocal provides a very easy way to achieve objects reusability with zero cost.

I had a situation where multiple threads were creating an image of mutable cache, on each update notification.

I used a Threadlocal on each thread, and then each thread would just need to reset old image and then update it again from the cache on each update notification.

Usual reusable objects from object pools have thread safety cost associated with them, while this approach has none.


D
DigitShifter

Try this small example, to get a feel for ThreadLocal variable:

public class Book implements Runnable {
    private static final ThreadLocal<List<String>> WORDS = ThreadLocal.withInitial(ArrayList::new);

    private final String bookName; // It is also the thread's name
    private final List<String> words;


    public Book(String bookName, List<String> words) {
        this.bookName = bookName;
        this.words = Collections.unmodifiableList(words);
    }

    public void run() {
        WORDS.get().addAll(words);
        System.out.printf("Result %s: '%s'.%n", bookName, String.join(", ", WORDS.get()));
    }

    public static void main(String[] args) {
        Thread t1 = new Thread(new Book("BookA", Arrays.asList("wordA1", "wordA2", "wordA3")));
        Thread t2 = new Thread(new Book("BookB", Arrays.asList("wordB1", "wordB2")));
        t1.start();
        t2.start();
    }
}

Console output, if thread BookA is done first: Result BookA: 'wordA1, wordA2, wordA3'. Result BookB: 'wordB1, wordB2'. Console output, if thread BookB is done first: Result BookB: 'wordB1, wordB2'. Result BookA: 'wordA1, wordA2, wordA3'.


A
Arvind Kumar

1st Use case - Per thread context which gives thread safety as well as performance Real-time example in SpringFramework classes -

LocaleContextHolder

TransactionContextHolder

RequestContextHolder

DateTimeContextHolder

2nd Use case - When we don't want to share something among threads and at the same time don't want to use synchronize/lock due to performance cost example - SimpleDateFormat to create the custom format for dates

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author - GreenLearner(https://www.youtube.com/c/greenlearner)
 */
public class ThreadLocalDemo1 {
    SimpleDateFormat sdf = new SimpleDateFormat("dd-mm-yyyy");//not thread safe
    ThreadLocal<SimpleDateFormat> tdl1 = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-dd-mm"));

    public static void main(String[] args) {
        ThreadLocalDemo1 d1 = new ThreadLocalDemo1();

        ExecutorService es = Executors.newFixedThreadPool(10);

        for(int i=0; i<100; i++) {
            es.submit(() -> System.out.println(d1.getDate(new Date())));
        }
        es.shutdown();
    }

    String getDate(Date date){

//        String s = tsdf.get().format(date);
        String s1 = tdl1.get().format(date);
        return s1;
    }
}

Usage Tips

Use local variables if possible. This way we can avoid using ThreadLocal

Delegate the functionality to frameworks as and when possible

If using ThreadLocal and setting the state into it then make sure to clean it after using otherwise it can become the major reason for OutOfMemoryError