为什么不在Java中使用实例对象而不是ThreadLocal?

时间:2018-04-08 23:36:05

标签: java multithreading concurrency thread-local

我正在阅读有关Java中ThreadLocal对象的this文章,试图理解为什么以及何时使用它们。在文章中,我遇到了一个示例,旨在演示如何使用ThreadLocal。这是一个应该是事务管理器的类,它使用了整个类中使用的静态transactionID变量。为了使类线程安全,它使用ThreadLocal作为transactionID:

public class TransactionManager {

    private static final ThreadLocal<String> context = new 
    ThreadLocal<String();

    public static void startTransaction() {
        //logic to start a transaction
        //...
        context.set(generatedId); 
    }
    public static String getTransactionId() {
        return context.get();
    }
    public static void endTransaction() {
        //logic to end a transaction
        //…
        context.remove();
    }
}

我的问题是,为什么不将transactionID设为实例变量而不是首先使其成为静态?这样你就不需要使用ThreadLocal变量了。

2 个答案:

答案 0 :(得分:1)

在某些情况下差异会发生变化,但让我们尝试一些事情:

我将假设示例的大纲类似于“我们正在某个进程中执行几个步骤,并且我们希望生成一个transactionID来标识进程的一个执行。所有这些步骤都在同一个线程中运行,用于任何给定的执行“

在这种情况下,不同之处在于,如果您将其设为实例变量(是的,您可以这样做),则必须创建transactionId并在您可能需要的所有层和类之间传播TransactionManager实例作为参数,使您的方法签名比需要的更脏(想象一下,您有一个StepExecution接口,并且所有步骤都实现了该接口,但并非所有步骤都可能需要访问transactionID,您将在方法签名中混合使用一个无用的参数)

不仅如此,ThreadLocal将保证您访问的值是您在同一线程上生成的值,防止线程之间的信息“泄漏”,使其完全线程安全。

答案 1 :(得分:-1)

  

...它使用了整个班级中使用的static transactionID变量。为了使类线程安全,它为ThreadLocal

使用了transactionID

简而言之,这基本上是 <{em>} ThreadLocal的用例:你有一些非线程感知代码,你想要使其成为线程安全的,但它使用了一个或更多静态变量。如果每个线程都有自己的静态变量的独立副本是有意义的,那么你只需弹出一个ThreadLocal,问题就解决了!