什么时候应该使用ThreadLocal变量?
它是如何使用的?
什么时候应该使用ThreadLocal变量?
它是如何使用的?
当前回答
线程局部变量通常用于防止基于线程的设计中的共享 可变单例或全局变量。
在不使用连接池的情况下,它可以用于为每个线程建立单独的JDBC连接等场景。
private static ThreadLocal<Connection> connectionHolder
= new ThreadLocal<Connection>() {
public Connection initialValue() {
return DriverManager.getConnection(DB_URL);
}
};
public static Connection getConnection() {
return connectionHolder.get();
}
当您调用getConnection时,它将返回与该线程关联的连接。对于其他属性(如dateformat、事务上下文等),您不希望在线程之间共享,也可以这样做。
您也可以使用局部变量来实现相同的目的,但是这些资源通常会占用创建时间,因此您不希望在使用它们执行某些业务逻辑时一次又一次地创建它们。然而,ThreadLocal值存储在线程对象本身中,一旦线程被垃圾收集,这些值也就消失了。
这个链接很好地解释了ThreadLocal的用法。
其他回答
[参考]ThreadLocal无法解决共享对象的更新问题。建议使用staticThreadLocal对象,该对象由同一线程中的所有操作共享。 [必选]remove()方法必须由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.
当您希望某些状态不应该在不同线程之间共享,但每个线程在其整个生命周期内都可以访问时,ThreadLocal非常有用。
As an example, imagine a web application, where each request is served by a different thread. Imagine that for each request you need a piece of data multiple times, which is quite expensive to compute. However, that data might have changed for each incoming request, which means that you can't use a plain cache. A simple, quick solution to this problem would be to have a ThreadLocal variable holding access to this data, so that you have to calculate it only once for each request. Of course, this problem can also be solved without the use of ThreadLocal, but I devised it for illustration purposes.
也就是说,请记住ThreadLocals本质上是一种全局状态的形式。因此,它有许多其他含义,只有在考虑了所有其他可能的解决方案后才应该使用。
线程局部变量通常用于防止基于线程的设计中的共享 可变单例或全局变量。
在不使用连接池的情况下,它可以用于为每个线程建立单独的JDBC连接等场景。
private static ThreadLocal<Connection> connectionHolder
= new ThreadLocal<Connection>() {
public Connection initialValue() {
return DriverManager.getConnection(DB_URL);
}
};
public static Connection getConnection() {
return connectionHolder.get();
}
当您调用getConnection时,它将返回与该线程关联的连接。对于其他属性(如dateformat、事务上下文等),您不希望在线程之间共享,也可以这样做。
您也可以使用局部变量来实现相同的目的,但是这些资源通常会占用创建时间,因此您不希望在使用它们执行某些业务逻辑时一次又一次地创建它们。然而,ThreadLocal值存储在线程对象本身中,一旦线程被垃圾收集,这些值也就消失了。
这个链接很好地解释了ThreadLocal的用法。
第一个用例——每个线程上下文,提供线程安全性和性能 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的主要原因