来自Java Concurrency in practice第 3.3.3 章。线程本地
线程局部变量通常用于防止在基于可变单例或全局变量的设计中共享。
如果我们将可变的 Singleton 人包装在 ThreadLocal 中,每个线程都会有自己的 Singleton 副本?那么它将如何保持单身呢?这是作者的意思还是我在这里遗漏了一些非常明显的东西?
来自Java Concurrency in practice第 3.3.3 章。线程本地
线程局部变量通常用于防止在基于可变单例或全局变量的设计中共享。
如果我们将可变的 Singleton 人包装在 ThreadLocal 中,每个线程都会有自己的 Singleton 副本?那么它将如何保持单身呢?这是作者的意思还是我在这里遗漏了一些非常明显的东西?
如果我们将可变的 Singleton 家伙包装在 ThreadLocal 中
AFAIK 你没有用 ThreadLocal 包装单例类,而是包含在单例中的对象是可变的或非线程安全的。正如该示例正确讨论的那样,JDBC 连接不是线程安全的,需要额外的保护,这反过来又增加了争用。
因此,在单例仅用于共享目的的情况下,将这些东西替换为 ThreadLocal 是一个好主意,因为所有线程都有自己的连接,不需要额外的保护。
ThreadLocal 用例的另一个很好的例子是随机生成,如果有一个Random
对象,那么线程内就会争用“种子”,所以如果每个线程都有自己的 Random 对象,那么就不再有争用了,这是有道理的.
如果您将单例(作为设计模式)包装在 ThreadLocal 中,它将保持为单例。ThreadLocal 没有什么大魔法,如果您检查一下刚刚看到的 ThreadLocal 的来源。它使用 Map 并使用当前线程作为键。所以在 ThreadLocal 中放置一个 Singleton(一个实现良好的)是非常没用的。因为您只能以各种方式获得相同的 Singleton。
我想作者的意思是,如果您的设计大量使用单例和/或全局变量,如果您需要每个线程唯一的东西,并且不想一直向下传递调用层次结构,那么 ThreadLocal 是一个不错的选择。但这东西与 Singleton 不同。当然你可以在你的 Singleton 中封装一个 ThreadLocal ,这样它就会有一些线程特定的状态(但我不会再调用 Singleton 了)
我对这一行的理解是,当应用程序的设计方式是 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();
}