7

我正在探索 Java 中的本地线程。我不明白为什么我们需要这门课。如果我只是简单地将一个新对象传递给每个线程以执行,我可以实现相同的目的,因为如果我使用 initialValue() 会发生同样的事情。我只是在 initialvalue() 中为每个线程返回一个新对象。

但是假设我有两个线程,ThreadOne:A 和 ThreadTwo B。现在我希望他们拥有自己的 SimpleDateFormat 类的副本。我可以通过在 ThreadLocal 类中扭曲 SimpleDateFormat 的对象然后使用 initialValue() 我可以返回 new SimpleDateFormat("yyyyMMdd HHmm"); 来做到这一点。我可以通过创建两个 SimpleDateFormat 的新对象并将 [每个传递一个给 ThreadOne 来实现相同的动机:A. 和 ThreadTwo :B. ThreadLocal 如何帮助我额外

问候,

4

4 回答 4

6

对于您的问题,这里已经有一些很好的例子。

但我尝试解释第二部分:

但是假设我有两个线程,ThreadOne:A 和 ThreadTwo B。现在我希望他们拥有自己的 SimpleDateFormat 类的副本。我可以通过在 ThreadLocal 类中扭曲 SimpleDateFormat 的对象然后使用 initialValue() 我可以返回 new SimpleDateFormat("yyyyMMdd HHmm"); 来做到这一点。我可以通过创建两个 SimpleDateFormat 的新对象并将 [每个传递一个给 ThreadOne 来实现相同的动机:A. 和 ThreadTwo :B. ThreadLocal 如何帮助我额外

通常,您需要以某种格式格式化日期,并且创建一次对象当然是一个好主意(而不是每次需要格式化日期时都SimpleDateFormat创建一个新对象)。SimpleDateFormat

所以你可能有这样的事情:

public class DateUtils {  
    private final static DateFormat dateFormat = new SimpleDateFormat("dd-mm-yyyy");  

    public String formatDate(Date date) {  
        return dateFormat.format(date);  
    }  
}  

如果多个线程同时调用,这将失败formatDate(...)(您可能会得到奇怪的输出或exceptions),因为SimpleDateFormatis not Thread-Safe. 为了使其线程安全,您可以使用ThreadLocal

public class DateUtils {  
    private final ThreadLocal<DateFormat> dateFormat = new ThreadLocal<DateFormat>() {  
        @Override  
        protected DateFormat initialValue() {  
            return new SimpleDateFormat("dd-mm-yyyy");  
        }  
    };  

    public String formatDate(Date date) {  
        return dateFormat.get().format(date);  
    }  
}  

现在每个对 formatDate() 方法的线程(或调用)都将在本地副本上工作,并且不会相互干扰。这为您提供了线程安全的行为。

于 2013-06-09T11:44:45.213 回答
1

线程局部存储服务于单个线程上下文中的全局变量。

考虑这个例子:你编写了一个多线程程序来处理用户请求。多个用户可以同时发起请求;您的系统为每个用户使用一个线程。

当用户请求到达时,您的系统会找出它来自的用户,并为该UserPermissions用户创建一个对象实例。

有几种方法可以使该对象对您正在运行的程序可用。一种方法是传递UserPermissions给可能需要它的每个方法,以及直接或间接调用可能需要它的方法的每个方法。这可能是有问题的,尤其是在使用回调的上下文中。

如果你的程序不是多线程的,你会设置UserPermissions一个全局变量。不幸的是,您不能这样做,因为多个用户请求可能同时处于活动状态。

这就是线程本地存储的用武之地:创建用户权限的进程将UserPermissions对象设置在线程本地存储中,并将其保留在那里,直到请求处理结束。这样,所有方法都可以UserPermissions根据需要抓取,而无需将它们作为方法参数传递。

于 2013-06-09T11:13:37.060 回答
0

本地线程是实现动态作用域的一种廉价方式。使用动态范围,在评估代码块期间存在绑定。在这种情况下,绑定存在于特定线程的执行期间。早期的 lisps 支持动态作用域,但它很少有意义,因此大多数现代编程语言不支持它,除非通过线程本地化。

动态范围/线程局部变量对于维护普遍的上下文信息很有用,例如:

有一个研究方向称为“面向上下文的编程”,旨在更好地支持编程语言中的此类问题。论文“面向上下文的编程:超越层”展示了一些进一步的例子。

于 2013-06-09T11:55:54.620 回答
0

您将使用ThreadLocal将“数据”传递给特定线程。
例如,您有一个方法doSomething(SomeObject a, SomeOtherObject b);
您可以通过线程局部变量以线程安全的方式将更多信息传递给此方法,以用于特定的执行线程,而不仅仅是ab

于 2013-06-09T11:02:13.090 回答