什么时候应该使用ThreadLocal变量?
它是如何使用的?
什么时候应该使用ThreadLocal变量?
它是如何使用的?
当前回答
Webapp服务器可能会保留一个线程池,并且在响应客户端之前应该删除ThreadLocal变量,因此当前线程可能会被下一个请求重用。
其他回答
Nothing really new here, but I discovered today that ThreadLocal is very useful when using Bean Validation in a web application. Validation messages are localized, but by default use Locale.getDefault(). You can configure the Validator with a different MessageInterpolator, but there's no way to specify the Locale when you call validate. So you could create a static ThreadLocal<Locale> (or better yet, a general container with other things you might need to be ThreadLocal and then have your custom MessageInterpolator pick the Locale from that. Next step is to write a ServletFilter which uses a session value or request.getLocale() to pick the locale and store it in your ThreadLocal reference.
Webapp服务器可能会保留一个线程池,并且在响应客户端之前应该删除ThreadLocal变量,因此当前线程可能会被下一个请求重用。
文档说得很好:“每个访问[线程局部变量]的线程(通过它的get或set方法)都有它自己的、独立初始化的变量副本”。
当每个线程必须有自己的某个副本时,可以使用一个。默认情况下,数据在线程之间共享。
缓存,有时你必须计算相同的值很多时间,所以通过存储最后一组输入到一个方法和结果,你可以加快代码。通过使用线程本地存储,您可以避免考虑锁定问题。
可以使用threadlocal变量的两个用例- 1-当我们需要将状态与线程关联时(例如,用户ID或事务ID)。这通常发生在web应用程序中,每个发送到servlet的请求都有一个与之关联的唯一transactionID。
// This class will provide a thread local variable which
// will provide a unique ID for each thread
class ThreadId {
// Atomic integer containing the next thread ID to be assigned
private static final AtomicInteger nextId = new AtomicInteger(0);
// Thread local variable containing each thread's ID
private static final ThreadLocal<Integer> threadId =
ThreadLocal.<Integer>withInitial(()-> {return nextId.getAndIncrement();});
// Returns the current thread's unique ID, assigning it if necessary
public static int get() {
return threadId.get();
}
}
注意,这里的withInitial方法是使用lambda表达式实现的。 2-另一个用例是当我们想要一个线程安全的实例时,我们不想使用同步,因为同步的性能成本更高。其中一种情况是使用SimpleDateFormat。由于SimpleDateFormat不是线程安全的,所以我们必须提供机制使其线程安全。
public class ThreadLocalDemo1 implements Runnable {
// threadlocal variable is created
private static final ThreadLocal<SimpleDateFormat> dateFormat = new ThreadLocal<SimpleDateFormat>(){
@Override
protected SimpleDateFormat initialValue(){
System.out.println("Initializing SimpleDateFormat for - " + Thread.currentThread().getName() );
return new SimpleDateFormat("dd/MM/yyyy");
}
};
public static void main(String[] args) {
ThreadLocalDemo1 td = new ThreadLocalDemo1();
// Two threads are created
Thread t1 = new Thread(td, "Thread-1");
Thread t2 = new Thread(td, "Thread-2");
t1.start();
t2.start();
}
@Override
public void run() {
System.out.println("Thread run execution started for " + Thread.currentThread().getName());
System.out.println("Date formatter pattern is " + dateFormat.get().toPattern());
System.out.println("Formatted date is " + dateFormat.get().format(new Date()));
}
}