我正在浏览ThreadLocal类文档,并想知道它可以在什么场景下使用。
首先,我认为它可以用于我们有第三方/遗留类并且我们想要处理同步问题的场景。然后我查看了ThreadLocal的其他示例,发现ThreadLocal不会有帮助,因为在大多数情况下,我们有单个对象,它在所有线程中共享。这是对的吗?
通过进一步理解,现在我可以考虑在每个线程需要一个单独对象的情况下使用ThreadLocal类,如果特定线程与ThreadLocal中的对象交互,则每次使用相同的对象而不是创建一个新的。
这是正确的还是我错过了什么?
答案 0 :(得分:10)
ThreadLocal最常用于在app服务器或servlet容器中实现每请求全局变量,其中每个用户/客户端请求由单独的线程处理。
例如,Spring,Spring Security和JSF都有“Context”的概念,通过它可以访问框架的功能。并且在每种情况下,在不能或不使用DI的情况下,通过依赖注入(干净方式)和将该上下文实现为ThreadLocal
。
这对于可维护性是不利的,因为它隐藏了依赖性,并且还直接导致问题,因为这样的容器使用线程池。他们必须使用反射删除请求之间的所有ThreadLocal
实例,以避免一个请求中的数据在另一个请求中出现(可能导致令人讨厌的安全问题)。有时它也会导致内存泄漏。
基本上,它是一种以黑客方式非常有用的功能,但也非常危险。如果可能的话,我建议你尽量避免使用它。
答案 1 :(得分:0)
另一个经常使用的应用程序是每个线程缓存,用于需要同步的对象,但必须避免开销。
例如:SimpleDateFormat
不是线程安全的 - 没有Format
。始终创建新实例效率不高。在多线程环境中同步一个实例也不高效。解决方案是:
class Foo
private final static ThreadLocal<SimpleDateFormat> threadLocal = new ThreadLocal<SimpleDateFormat>(){
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat(pattern);
}
};
public void doStuff(){
SimpleDateFormat df = threadLocal.get();
// use df
}
}