【问题标题】:Why Not Use Instance Objects Instead of ThreadLocal in Java? [closed]为什么不使用实例对象而不是 Java 中的 ThreadLocal? [关闭]
【发布时间】:2018-09-18 07:34:18
【问题描述】:

我正在阅读 this 关于 Java 中的 ThreadLocal 对象的文章,试图了解为什么以及何时使用它们。在文章中,我遇到了一个示例,旨在演示如何使用 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 变量。

【问题讨论】:

  • 因为那么你需要一个单独的TransactionManager每个线程,你不能静态调用TransactionManager.startTransaction()
  • @chrylis 每个线程有一个单独的TransactionManager 是否有缺点,例如开销?
  • 相对于全局?每线程通常必要以确保正确处理。

标签: java multithreading concurrency thread-local


【解决方案1】:

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

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

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

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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-06-10
      • 2013-10-31
      • 1970-01-01
      • 2011-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多