什么时候应该使用ThreadLocal变量?

它是如何使用的?


当前回答

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

其他回答

在多线程代码中使用类似SimpleDateFormat的类助手有三种场景,其中最好的一种是使用ThreadLocal

场景

1-通过锁或同步机制使用类似的共享对象,使应用程序变慢

线程池操作场景

2-在方法中作为局部对象使用

在线程池中,在这个场景中,如果我们有4个线程每个线程有1000个任务时间,那么我们有 创建了4000 SimpleDateFormat对象,并等待GC删除它们

3-使用ThreadLocal

在线程池中,如果我们有4个线程,我们给每个线程一个SimpleDateFormat实例 我们有4个线程,4个SimpleDateFormat对象。

不需要锁机制和对象的创建和销毁。(良好的时间复杂度和空间复杂度)

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

一种可能的(也是常见的)用途是,当您有一些不是线程安全的对象,但您希望避免同步访问该对象(我正在看您,SimpleDateFormat)。相反,给每个线程它自己的对象实例。

例如:

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

文档。

[参考]ThreadLocal无法解决共享对象的更新问题。建议使用staticThreadLocal对象,该对象由同一线程中的所有操作共享。 [必选]remove()方法必须由ThreadLocal变量实现,特别是在使用经常重用线程的线程池时。否则,可能会影响后续的业务逻辑,并导致意想不到的问题,如内存泄漏。

Threadlocal提供了一种非常简单的零成本实现对象可重用性的方法。

我遇到过这样一种情况,在每次更新通知时,多个线程都在创建可变缓存的映像。

我在每个线程上使用Threadlocal,然后每个线程只需要重置旧映像,然后在每次更新通知时从缓存中再次更新它。

来自对象池的通常可重用对象具有与之相关的线程安全成本,而此方法没有。

缓存,有时你必须计算相同的值很多时间,所以通过存储最后一组输入到一个方法和结果,你可以加快代码。通过使用线程本地存储,您可以避免考虑锁定问题。