【问题标题】:Advice on using ThreadLocals to wrap mutable singleton objects关于使用 ThreadLocals 包装可变单例对象的建议
【发布时间】:2013-01-25 01:18:15
【问题描述】:

来自Java Concurrency in practice 第 3.3.3 章。 线程本地

线程局部变量通常用于防止设计中的共享 基于可变单例或全局变量。

如果我们将可变的 Singleton 人包装在 ThreadLocal 中,每个线程都会有自己的 Singleton 副本?那么它将如何保持单身呢?这是作者的意思还是我在这里遗漏了一些很明显的东西?

【问题讨论】:

    标签: java multithreading thread-local


    【解决方案1】:

    我对这一行的理解是,当应用程序的设计方式是 Singleton 类具有可变状态且被许多线程读取和写入时,将需要线程安全,因此您需要序列化对该状态的所有访问.您可以考虑在该可变单例上创建一个 ThreadLocal 。 (来自书中:-) 例如,单线程应用程序可能会维护一个在启动时初始化的全局数据库连接,以避免必须将 Connection 传递给每个方法。由于 JDBC 连接可能不是线程安全的,因此使用全局连接而没有额外协调的多线程应用程序也不是线程安全的。通过使用 ThreadLocal 来存储 JDBC 连接,如清单 3.10 中的 ConnectionHolder,每个线程都有自己的连接。

    private static ThreadLocal<Connection> connectionHolder= new ThreadLocal<Connection>() {
          public Connection initialValue() {
      return DriverManager.getConnection(DB_URL);
      }
     };
       public static Connection getConnection() {
         return connectionHolder.get();
         }
    

    【讨论】:

      【解决方案2】:

      如果我们将可变的 Singleton 家伙包装在 ThreadLocal 中

      AFAIK 你没有用 ThreadLocal 包装单例类,而是包含在单例中的对象是可变或非线程安全的。正如该示例正确讨论的那样,JDBC 连接 不是线程安全的,需要额外的保护,这反过来又增加了争用。

      因此,如果 Singleton 仅用于共享目的,那么将这些东西替换为 ThreadLocal 是个好主意,因为所有线程都有自己的 Connection,不需要额外的保护。

      ThreadLocal 用例的另一个很好的例子是 Random 生成,如果有单个 Random 对象,则线程内会争用 "seed",因此,如果每个线程都有自己的 Random 对象,则不再存在争用,这是有道理的。

      【讨论】:

      • 你的意思是“你没有用 ThreadLocal 包装单例类,而是包含在单例中的对象是可变的或非线程安全的”。你能详细说明一下吗?
      • 我的意思是单例是你用来共享对象的容器。像 ConnectionManager 单例将用于共享 DB 连接对象。因此,您不包装连接管理器,而是将连接包装在 ThreadLocal(线程限制)中,从而使可变且非线程安全的连接变得安全。我希望这是有道理的。
      • 是的,确实有道理。我认为书中的引述是模棱两可的。你怎么看?
      • 我认为作者试图解释当你使用单例来共享可变数据时,Threadlocals 是更好的选择。此外,单例模式更像是一种反测试模式。
      • 如果我们使用线程局部变量,逻辑上我们最终会拥有同一个共享对象的多个实例。那么单例在这里有什么帮助呢?毕竟内部对象现在有很多。那么我们应该在 Singleton 对象中使用可变状态吗?我没有得到将可变对象用作单例的意义。某个线程很有可能会修改对象的状态。而在这种情况下,我们需要自己管理线程安全。
      【解决方案3】:

      如果您将单例(作为设计模式)包装在 ThreadLocal 中,它将保持为单例。 ThreadLocal 没有什么大魔法,如果您检查一下刚刚看到的 ThreadLocal 的来源。它使用 Map 并使用当前线程作为键。所以在 ThreadLocal 中放置一个 Singleton(一个实现良好的)是非常没用的。因为您只能通过各种方式获得相同的 Singleton。

      我想作者的意思是,如果您的设计大量使用单例和/或全局变量,如果您需要每个线程唯一的东西,并且不想一直向下传递调用层次结构,那么 ThreadLocal 是一个不错的选择。但这东西与 Singleton 不同。当然,您可以在 Singleton 中封装一个 ThreadLocal,这样它就会有一些特定于线程的状态(但我不会再调用 Singleton)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-10-10
        相关资源
        最近更新 更多