Java并发编程实践第三章对象的共享

3.3.3  ThreadLocal
3.3.3   ThreadLocal

A more formal means of maintaining thread confinement is ThreadLocal,which allows you to associate a per-thread value with a value-holding object. ThreadLocal provides get and set accessor methods that maintain a separate copy of the value for each thread that uses it, so a get returns the most recent value passed to set from the currently executing thread.
ThreadLocal是维护线程边界的更加正式的方式。通过ThreadLocal,你可以把一个per thread的值和一个值对象关联在一起。ThreadLocal的get和set方法为调用该方法的每个线程维护值对象的一个独立拷贝,因此get方法会返回当前线程设置的最新值。

Thread-local variables are often used to prevent sharing in designs based on mutable Singletons or global variables. For example, a single-threaded application might maintain a global database connection that is initialized at startup to avoid having to pass a Connection to every method. Since JDBC connections may not be thread-safe, a multithreaded application that uses a global connection without additional coordination is not thread-safe either. By using a ThreadLocal to store the JDBC connection, as in ConnectionHolder in Listing 3.10, each thread will have its own 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(); }

Listing 3.10.Using ThreadLocal to ensure thread confinement
表3.10. 用ThreadLocal保证线程边界

This technique can also be used when a frequently used operation requires a temporary object such as a buffer and wants to avoid reallocating the temporary object on each invocation. For example, before Java 5.0, Integer.toString used a ThreadLocal to store the 12-byte buffer used for formatting its result, rather than using a shared static buffer (which would require locking) or allocating a new buffer for each invocation.[11]
ThreadLocal还经常用在如下场合--你要频繁调用某操作而该操作又需要一个临时对象比如缓冲区,但你又不想每次调用都重新分配这个临时对象。例如,Java 5.0之前的版本Integer.toString的做法就是用ThreadLocal来存储一个用于格式化结果的12字节缓冲区,而不是用一个共享的静态缓冲区也不是在每次调用的时候重新分配一个缓冲区。[11]

When a thread calls ThreadLocal.get for the first time, initialValue is consulted to provide the initial value for that thread. Conceptually, you can think of a ThreadLocal<T> as holding a Map<Thread,T> that stores the thread-specific values, though this is not how it is actually implemented. The thread-specific values are stored in the Thread object itself; when the thread terminates, the thread-specific values can be garbage collected.
当线程第一次调用ThreadLocal.get时,initialValue会用于为该线程提供初始值。你一个把ThreadLocal<T>当作Map<Thread,T>来存储线程特定的值,但ThreadLocal<T>实际上并不是用Map<Thread,T>来实现的。线程特定的值存储在线程对象自身当中--当线程终止,线程相关的值也就变成可回收状态了。

If you are porting a single-threaded application to a multithreaded environment, you can preserve thread safety by converting shared global variables into ThreadLocals, if the semantics of the shared globals permits this; an application-wide cache would not be as useful if it were turned into a number of thread-local caches.
如果要把单线程程序移植到多线程环境,你可以通过把共享对象转换成ThreadLocal来实现线程安全,只要这样做不违反共享的全局变量的语义。把应用范围内的缓存变成线程局部缓存就没有多大意义了。

ThreadLocal is widely used in implementing application frameworks. For example, J2EE containers associate a transaction context with an executing thread for the duration of an EJB call. This is easily implemented using a static ThreadLocal holding the transaction context: when framework code needs to determine what transaction is currently running, it fetches the transaction context from this ThreadLocal. This is convenient in that it reduces the need to pass execution context information into every method, but couples any code that uses this mech-
anism to the framework.
ThreadLocal被广泛用于实现应用程序框架。例如,J2EE容器在调用EJB时会将事务的上下文与执行线程关联在一起。用一个静态的ThreadLocal来保存事务上下文就很容易的达到这一目的--当框架代码需要知道哪个事务正在运行的时候,只要从ThreadLocal中取出事务向下午就好了。这样做的方便之处在于你不必要把程序执行的上下文信息传给每个方法,但坏处是要和框架绑在一起了。

It is easy to abuse ThreadLocal by treating its thread confinement property as a license to use global variables or as a means of creating “hidden” method arguments. Like global variables, thread-local variables can detract from reusability and introduce hidden couplings among classes, and should therefore be used with care.
ThreadLocal也容易被滥用,比如把它的线程边界特性用作全局变量或创建“隐藏”的方法参数。象全局变量一样,线程局部变量也会减低复用性并造成类之间的隐含耦合,因此我们应该谨慎使用ThreadLocal。

3.4  Immutability
3.4  不可变性

The other end-run around the need to synchronize is to use immutable objects[EJ Item 13]. Nearly all the atomicity and visibility hazards we’ve described so far, such as seeing stale values, losing updates, or observing an object to be in an inconsistent state, have to do with the vagaries of multiple threads trying to access the same mutable state at the same time. If an object’s state cannot be modified, these risks and complexities simply go away.
解决同步需求的另一种截然不同的方法是使用不可变对象[EJ第13条]。

原文地址:https://www.cnblogs.com/littlesuccess/p/2215417.html