When and how should I use a ThreadLocal variable?

前端 未结 25 1933
再見小時候
再見小時候 2020-11-22 12:35

When should I use a ThreadLocal variable?

How is it used?

相关标签:
25条回答
  • 2020-11-22 13:17

    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.

    0 讨论(0)
  • 2020-11-22 13:18

    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();
    
    }
    }
    
    0 讨论(0)
  • 2020-11-22 13:20

    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.

    0 讨论(0)
  • 2020-11-22 13:20

    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.

    0 讨论(0)
  • 2020-11-22 13:20

    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'.

    0 讨论(0)
  • 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.

    0 讨论(0)
提交回复
热议问题