什么时候应该使用ThreadLocal变量?
它是如何使用的?
什么时候应该使用ThreadLocal变量?
它是如何使用的?
当前回答
ThreadLocal in Java had been introduced on JDK 1.2 but was later generified in JDK 1.5 to introduce type safety on ThreadLocal variable. ThreadLocal can be associated with Thread scope, all the code which is executed by Thread has access to ThreadLocal variables but two thread can not see each others ThreadLocal variable. Each thread holds an exclusive copy of ThreadLocal variable which becomes eligible to Garbage collection after thread finished or died, normally or due to any Exception, Given those ThreadLocal variable doesn't have any other live references. ThreadLocal variables in Java are generally private static fields in Classes and maintain its state inside Thread.
阅读更多:Java示例程序和教程中的ThreadLocal
其他回答
在Java中,如果您有一个每个线程都可以变化的数据,那么您可以选择将该数据传递给每个需要(或可能需要)它的方法,或者将该数据与线程关联。如果你的所有方法都需要传递一个公共的“上下文”变量,那么到处传递数据可能是可行的。
如果不是这样,您可能不希望用额外的参数来打乱方法签名。在非线程环境中,可以使用Java中等价的全局变量来解决这个问题。在线程词中,与全局变量等价的是线程局部变量。
Webapp服务器可能会保留一个线程池,并且在响应客户端之前应该删除ThreadLocal变量,因此当前线程可能会被下一个请求重用。
在《Java并发实践》一书中有一个很好的例子。作者(Joshua Bloch)解释了线程限制是实现线程安全的最简单方法之一,而ThreadLocal是维护线程限制的更正式的方法。最后,他还解释了人们如何滥用它作为全局变量。
我已经从提到的书中复制了文本,但代码3.10是缺失的,因为它不太重要,了解ThreadLocal应该在哪里使用。
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. 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 Thread-Local 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 mechanism to the framework. 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.
Many frameworks use ThreadLocals to maintain some context related to the current thread. For example when the current transaction is stored in a ThreadLocal, you don't need to pass it as a parameter through every method call, in case someone down the stack needs access to it. Web applications might store information about the current request and session in a ThreadLocal, so that the application has easy access to them. With Guice you can use ThreadLocals when implementing custom scopes for the injected objects (Guice's default servlet scopes most probably use them as well).
ThreadLocals are one sort of global variables (although slightly less evil because they are restricted to one thread), so you should be careful when using them to avoid unwanted side-effects and memory leaks. Design your APIs so that the ThreadLocal values will always be automatically cleared when they are not needed anymore and that incorrect use of the API won't be possible (for example like this). ThreadLocals can be used to make the code cleaner, and in some rare cases they are the only way to make something work (my current project had two such cases; they are documented here under "Static Fields and Global Variables").
什么时候?
当一个对象不是线程安全的时候,为了避免影响可伸缩性的同步,给每个线程一个对象,并保持它的线程作用域,即ThreadLocal。最常用但不是线程安全的对象之一是数据库Connection和JMSConnection。
如何?
例如,Spring框架通过将这些连接对象保存在ThreadLocal变量中,在幕后大量使用ThreadLocal来管理事务。在高层,当事务启动时,它获得连接(并禁用自动提交)并将其保存在ThreadLocal中。在进一步的db调用中,它使用相同的连接与db通信。最后,它从ThreadLocal获取连接,提交(或回滚)事务并释放连接。
我认为log4j也使用ThreadLocal来维护MDC。