什么时候应该使用ThreadLocal变量?
它是如何使用的?
什么时候应该使用ThreadLocal变量?
它是如何使用的?
当前回答
ThreadLocal will ensure accessing the mutable object by the multiple threads in the non synchronized method is synchronized, means making the mutable object to be immutable within the method. This is achieved by giving new instance of mutable object for each thread try accessing it. So It is local copy to the each thread. This is some hack on making instance variable in a method to be accessed like a local variable. As you aware method local variable is only available to the thread, one difference is; method local variables will not available to the thread once method execution is over where as mutable object shared with threadlocal will be available across multiple methods till we clean it up.
通过定义:
Java中的ThreadLocal类允许您创建这样的变量 只能在同一线程上读写。这样,即使是两个线程 正在执行相同的代码,并且该代码有一个对 变量ThreadLocal,那么两个线程不能看到彼此的线程 ThreadLocal变量。
java中的每个线程都包含ThreadLocalMap。 在哪里
Key = One ThreadLocal object shared across threads.
value = Mutable object which has to be used synchronously, this will be instantiated for each thread.
实现ThreadLocal:
现在为ThreadLocal创建一个包装器类,它将保存如下所示的可变对象(有或没有initialValue())。现在这个包装器的getter和setter将工作于threadlocal实例,而不是可变对象。
如果threadlocal的getter()在线程的threadlocalmap中没有找到任何值;然后它将调用initialValue()来获得它相对于线程的私有副本。
class SimpleDateFormatInstancePerThread {
private static final ThreadLocal<SimpleDateFormat> dateFormatHolder = new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd") {
UUID id = UUID.randomUUID();
@Override
public String toString() {
return id.toString();
};
};
System.out.println("Creating SimpleDateFormat instance " + dateFormat +" for Thread : " + Thread.currentThread().getName());
return dateFormat;
}
};
/*
* Every time there is a call for DateFormat, ThreadLocal will return calling
* Thread's copy of SimpleDateFormat
*/
public static DateFormat getDateFormatter() {
return dateFormatHolder.get();
}
public static void cleanup() {
dateFormatHolder.remove();
}
}
现在wrapper.getDateFormatter()将调用threadlocal.get()并检查currentThread。threadLocalMap包含这个(threadlocal)实例。 如果是,返回对应threadlocal实例的值(SimpleDateFormat) 否则使用这个threadlocal实例initialValue()添加映射。
在此可变类上实现线程安全;每个线程都使用自己的可变实例,但使用相同的ThreadLocal实例。意味着所有线程将共享相同的ThreadLocal实例作为key,但不同的SimpleDateFormat实例作为value。
https://github.com/skanagavelu/yt.tech/blob/master/src/ThreadLocalTest.java
其他回答
第一个用例——每个线程上下文,提供线程安全性和性能 SpringFramework类中的实时示例-
LocaleContextHolder TransactionContextHolder RequestContextHolder DateTimeContextHolder
第二个用例——当我们不想在线程之间共享一些东西,同时由于性能成本而不想使用同步/锁定时 SimpleDateFormat为日期创建自定义格式
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author - GreenLearner(https://www.youtube.com/c/greenlearner)
*/
public class ThreadLocalDemo1 {
SimpleDateFormat sdf = new SimpleDateFormat("dd-mm-yyyy");//not thread safe
ThreadLocal<SimpleDateFormat> tdl1 = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-dd-mm"));
public static void main(String[] args) {
ThreadLocalDemo1 d1 = new ThreadLocalDemo1();
ExecutorService es = Executors.newFixedThreadPool(10);
for(int i=0; i<100; i++) {
es.submit(() -> System.out.println(d1.getDate(new Date())));
}
es.shutdown();
}
String getDate(Date date){
// String s = tsdf.get().format(date);
String s1 = tdl1.get().format(date);
return s1;
}
}
使用技巧
尽可能使用局部变量。这样我们就可以避免使用ThreadLocal 尽可能地将功能委托给框架 如果使用ThreadLocal并将状态设置在其中,请确保在使用后清理它,否则它可能成为OutOfMemoryError的主要原因
ThreadLocal will ensure accessing the mutable object by the multiple threads in the non synchronized method is synchronized, means making the mutable object to be immutable within the method. This is achieved by giving new instance of mutable object for each thread try accessing it. So It is local copy to the each thread. This is some hack on making instance variable in a method to be accessed like a local variable. As you aware method local variable is only available to the thread, one difference is; method local variables will not available to the thread once method execution is over where as mutable object shared with threadlocal will be available across multiple methods till we clean it up.
通过定义:
Java中的ThreadLocal类允许您创建这样的变量 只能在同一线程上读写。这样,即使是两个线程 正在执行相同的代码,并且该代码有一个对 变量ThreadLocal,那么两个线程不能看到彼此的线程 ThreadLocal变量。
java中的每个线程都包含ThreadLocalMap。 在哪里
Key = One ThreadLocal object shared across threads.
value = Mutable object which has to be used synchronously, this will be instantiated for each thread.
实现ThreadLocal:
现在为ThreadLocal创建一个包装器类,它将保存如下所示的可变对象(有或没有initialValue())。现在这个包装器的getter和setter将工作于threadlocal实例,而不是可变对象。
如果threadlocal的getter()在线程的threadlocalmap中没有找到任何值;然后它将调用initialValue()来获得它相对于线程的私有副本。
class SimpleDateFormatInstancePerThread {
private static final ThreadLocal<SimpleDateFormat> dateFormatHolder = new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd") {
UUID id = UUID.randomUUID();
@Override
public String toString() {
return id.toString();
};
};
System.out.println("Creating SimpleDateFormat instance " + dateFormat +" for Thread : " + Thread.currentThread().getName());
return dateFormat;
}
};
/*
* Every time there is a call for DateFormat, ThreadLocal will return calling
* Thread's copy of SimpleDateFormat
*/
public static DateFormat getDateFormatter() {
return dateFormatHolder.get();
}
public static void cleanup() {
dateFormatHolder.remove();
}
}
现在wrapper.getDateFormatter()将调用threadlocal.get()并检查currentThread。threadLocalMap包含这个(threadlocal)实例。 如果是,返回对应threadlocal实例的值(SimpleDateFormat) 否则使用这个threadlocal实例initialValue()添加映射。
在此可变类上实现线程安全;每个线程都使用自己的可变实例,但使用相同的ThreadLocal实例。意味着所有线程将共享相同的ThreadLocal实例作为key,但不同的SimpleDateFormat实例作为value。
https://github.com/skanagavelu/yt.tech/blob/master/src/ThreadLocalTest.java
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").
Webapp服务器可能会保留一个线程池,并且在响应客户端之前应该删除ThreadLocal变量,因此当前线程可能会被下一个请求重用。
正如@unknown(谷歌)所提到的,它的用途是定义一个全局变量,其中引用的值在每个线程中都是唯一的。它的使用通常需要存储某种链接到当前执行线程的上下文信息。
我们在Java EE环境中使用它来将用户标识传递给不支持Java EE的类(不能访问HttpSession或EJB SessionContext)。通过这种方式,代码可以从任何地方访问标识,而不必在每个方法调用中显式地传递它。
大多数Java EE调用中的操作的请求/响应周期使得这种类型的使用很容易,因为它提供了定义良好的入口和出口点来设置和取消设置ThreadLocal。