3

我仍然对 ThreadLocal 的概念感到困惑。我已经阅读了 JavaDoc,以及此处发布的其他相关问题,但是所使用的行话并没有对我有太大帮助。

我有点理解 ThreadLocal,也就是说,每个线程都有自己的变量副本。那么……这与说……每次都构造新变量有何不同?

例如,以 DateFormatter 为例:

public void convertDate(String date) 
{ 
    // Contruct new date formatter for every invocation of the method.
    DateFormatter df = new SimpleDateFormatter(...);
    ....
}

public void convertDate(String date) 
{ 
    // Getting date formatter from threadlocal.
    DateFormatter df = threadLocal.get();
    ....
}

如果第二个所做的只是返回变量的新副本,那么第一个与第二个有何不同?

谢谢。

4

3 回答 3

10

ThreadLocal 对象通常是静态的,这意味着它们在同一线程内的函数调用之间保留其值。

在您的第一个代码片段中,每次convertDate调用时,SimpleDateFormatter都会创建一个新对象。在第二个片段中,SimpleDateFormatter每个线程创建一个对象。get()每次convertDate在同一个线程中调用该方法都会返回同一个对象。

ThreadLocal 对象在实现线程本地存储方面很有用,这意味着为每个线程维护单独的变量实例。

于 2009-05-17T01:33:06.793 回答
1

如果第二个方法每次都在不同的线程中调用,那么您的两个示例是相同的。在这种情况下,第一个示例更有效。

但是,如果您在同一个线程中多次调用同一个方法,它将缓存该线程的值,而不必每次都创建一个新对象。(大多数与日期相关的对象都相当昂贵,在这种情况下值得这样做)在这种情况下,在线程中重用同一个对象有一点性能优势。

注意:线程本地对象存储在附加到线程本身的映射中。如果线程死亡,则该线程本地的所有对象都将被 GC。这就是 ThreadLocal 可以比大多数缓存更简单的地方。

于 2009-05-17T05:33:36.737 回答
1

有几种不同的用途ThreadLocal

与您的示例一样,可以缓存构造成本高、线程不安全的对象。然后可以以安全的方式使用该对象,而无需每次使用的构造开销。这不一定是胜利(例如,使用更多非本地内存),但它可能是。

它还可以用于通过上下文参数“欺骗”到并非设计为具有上下文的回调中。或者只是为了让界面更简单。在这种情况下,对 的规范引用ThreadLocal可能不是静态的。该对象也可能是故意可变的。我不太喜欢鼓励这种技术,但有些人(比如“疯狂”的 Bob Lee)喜欢它。

ThreadLocal当您将任务分叉到多个线程时效果不佳。InheritableThreadLocal似乎没有什么好的用途。

于 2009-05-17T02:01:22.967 回答