我在这里阅读Threadlocal的JavaDoc
https://docs.oracle.com/javase/1.5.0/docs/api/java/lang/ThreadLocal.html
它说:“ ThreadLocal实例通常是希望将状态与线程关联的类中的私有静态字段(例如,用户ID或事务ID)。”
但是我的问题是,为什么他们选择使其静态化(通常)-使其具有“每个线程”状态,但字段是静态的则有些令人困惑?
我在这里阅读Threadlocal的JavaDoc
https://docs.oracle.com/javase/1.5.0/docs/api/java/lang/ThreadLocal.html
它说:“ ThreadLocal实例通常是希望将状态与线程关联的类中的私有静态字段(例如,用户ID或事务ID)。”
但是我的问题是,为什么他们选择使其静态化(通常)-使其具有“每个线程”状态,但字段是静态的则有些令人困惑?
Answers:
因为如果它是一个实例级字段,则实际上是“每个线程-每个实例”,而不仅仅是保证的“每个线程”。通常这不是您要查找的语义。
通常,它所保存的对象之类的对象仅限于用户对话,Web请求等。您不希望它们也被细分为类的实例。
一个Web请求=>一个Persistence会话。
没有一个Web请求=>每个对象一个持久性会话。
ThreadLocal
来保存对将对象映射到每个线程实例的哈希集的引用。
ThreadLocal
将保存其自己的线程本地数据,即使这些ThreadLocal
实例存在于同一线程中也是如此。这样做不一定是错误的-我想这可能是两者中最不受欢迎的模式
将其设置为静态,或者尝试避免类中的任何静态字段-将类本身设置为单例,然后只要在全球范围内都可以使用实例级ThreadLocal,就可以安全地使用该实例级的ThreadLocal。
在每个线程的每个实例的每个线程上使用threadlocal的情况是,如果您希望某个对象在对象的所有方法中均可见,并且使其具有线程安全性,而又不像对普通字段那样对它进行同步访问。
static final ThreadLocal
变量是线程安全的。
static
使ThreadLocal变量在多个类中仅对相应线程可用。这是跨多个类的各个线程局部变量的全局变量描述。
我们可以使用以下代码示例检查此线程的安全性。
CurrentUser
-将当前用户ID存储在ThreadLocal中TestService
-具有方法的简单服务- getUser()
从CurrentUser获取当前用户。TestThread
-此类用于创建多个线程并同时设置用户ID。
public class CurrentUser
public class CurrentUser {
private static final ThreadLocal<String> CURRENT = new ThreadLocal<String>();
public static ThreadLocal<String> getCurrent() {
return CURRENT;
}
public static void setCurrent(String user) {
CURRENT.set(user);
}
}
public class TestService {
public String getUser() {
return CurrentUser.getCurrent().get();
}
}
。
import java.util.ArrayList;
import java.util.List;
public class TestThread {
public static void main(String[] args) {
List<Integer> integerList = new ArrayList<>();
//creates a List of 100 integers
for (int i = 0; i < 100; i++) {
integerList.add(i);
}
//parallel stream to test concurrent thread execution
integerList.parallelStream().forEach(intValue -> {
//All concurrent thread will set the user as "intValue"
CurrentUser.setCurrent("" + intValue);
//Thread creates a sample instance for TestService class
TestService testService = new TestService();
//Print the respective thread name along with "intValue" value and current user.
System.out.println("Start-"+Thread.currentThread().getName()+"->"+intValue + "->" + testService.getUser());
try {
//all concurrent thread will wait for 3 seconds
Thread.sleep(3000l);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//Print the respective thread name along with "intValue" value and current user.
System.out.println("End-"+Thread.currentThread().getName()+"->"+intValue + "->" + testService.getUser());
});
}
}
。
运行TestThread主类。输出-
Start-main->62->62
Start-ForkJoinPool.commonPool-worker-2->31->31
Start-ForkJoinPool.commonPool-worker-3->81->81
Start-ForkJoinPool.commonPool-worker-1->87->87
End-main->62->62
End-ForkJoinPool.commonPool-worker-1->87->87
End-ForkJoinPool.commonPool-worker-2->31->31
End-ForkJoinPool.commonPool-worker-3->81->81
Start-ForkJoinPool.commonPool-worker-2->32->32
Start-ForkJoinPool.commonPool-worker-3->82->82
Start-ForkJoinPool.commonPool-worker-1->88->88
Start-main->63->63
End-ForkJoinPool.commonPool-worker-1->88->88
End-main->63->63
...
分析总结
main
执行结束并显示当前用户为“ 62”,并行ForkJoinPool.commonPool-worker-1
执行结束并显示当前用户为“ 87”,并行ForkJoinPool.commonPool-worker-2
执行结束并显示当前用户为“ 31”,并行ForkJoinPool.commonPool-worker-3
执行结束并显示当前用户为“ 81”推理
并发线程即使已声明为“静态最终ThreadLocal”,也能够检索正确的用户ID。