Java 为什么ThreadLocal变量需要静态?
我读过很多关于为什么Java 为什么ThreadLocal变量需要静态?,java,multithreading,Java,Multithreading,我读过很多关于为什么ThreadLocal变量需要是静态的文章(虽然不是必需的),但我不明白为什么它应该是静态的 我读过它和许多其他链接,但没有想到 我做过类似的事情 public class ThreadLocalDemo{ public static void main(String[]args)throws Exception{ SharedRersource r1= new SharedRersource(); Thread t1= new Th
ThreadLocal
变量需要是静态的文章(虽然不是必需的),但我不明白为什么它应该是静态的
我读过它和许多其他链接,但没有想到
我做过类似的事情
public class ThreadLocalDemo{
public static void main(String[]args)throws Exception{
SharedRersource r1= new SharedRersource();
Thread t1= new Thread(r1);
Thread t2= new Thread(r1);
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("Main thread Exiting...");
}
}
class SharedRersource implements Runnable{
private ThreadLocal<Integer> threadId = new ThreadLocal(){
protected Integer initialValue(){
return (int)(Math.random()*100);
}
};
public void run(){
try{
Thread.sleep(2000);
}
catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(threadId.get());
}
};
public类ThreadLocalDemo{
公共静态void main(字符串[]args)引发异常{
SharedResource r1=新的SharedResource();
螺纹t1=新螺纹(r1);
螺纹t2=新螺纹(r1);
t1.start();
t2.start();
t1.join();
t2.连接();
System.out.println(“主线程退出…”);
}
}
类SharedResource实现可运行{
private ThreadLocal threadId=new ThreadLocal(){
受保护的整数初始值(){
返回值(int)(Math.random()*100);
}
};
公开募捐{
试一试{
《睡眠》(2000年);
}
捕捉(中断异常e){
e、 printStackTrace();
}
System.out.println(threadId.get());
}
};
这里线程t1和t2拥有threadId的私有副本,而不是为什么它应该是静态的
请给我一个更好的理解。
感谢您的实现,您(逻辑上)拥有了
threadID
的4个不同实例:
r1.threadID{t1}
-实例保存在资源r1
中,由线程t1
观察。如果中断,它将通过线程t1
打印r2.threadID{t2}
-实例保存在资源r2
中,由线程t2
观察。如果中断,它将通过线程t2
打印r1.threadID{t2}
-实例保存在resourcer1
中,在case中由线程t2
观察,例如,如果它(直接)调用r1.run()
r2.threadID{t2}
-实例保存在resourcer2
中,由线程t1
在case中观察,例如,如果它(直接)调用r2.run()
- 使变量为静态
threadID{t1}
,由threadt1
观察,和threadID{t2}
,由threadt2
观察
- 将变量设为非ThreadLocal
r1.threadID
,通过r1
(通过threadt1
)观察;和r2.threadID
,通过r2
(通过threadt2
)观察。ThreadLocal
变量需要是静态的,没有内在原因。只是,ThreadLocal
解决的问题通常只发生在基于static-y设计思想的程序中
在我看来,您最有可能在最初是单线程的代码中找到ThreadLocal
,直到有人将其“升级”为使用多线程。当大量代码最初引用某个静态变量时,线程局部就很方便了,现在您需要在同一代码体中运行的每个线程都有自己的副本
在我看来,
ThreadLocal
是一种代码气味——一种糟糕设计的标志。一个设计良好的多线程程序不需要它。AThreadLocal
不需要是静态的。就像其他变量一样,它取决于您的意图:
public class FooClass {
static Integer staticVar // 1 per process
Integer var; // 1 per instance
static ThreadLocal<Integer> staticThreadLocalVar; // 1 per thread
ThreadLocal<Integer> threadLocalVar; // 1 per thread per instance
}
公共类{
静态整数staticVar//1每个进程
整型变量;//每个实例1
static ThreadLocal staticThreadLocalVar;//每个线程1
ThreadLocal threadLocalVar;//每个实例每个线程1个
}
你所给的报价正是指上面列出的第三个案例
ThreadLocal实例通常是类中的私有静态字段
希望将状态与线程关联的
但是,在某些情况下,将状态与每个实例的线程相关联可能是完全合理的,在这种情况下,您可能希望使用
非静态ThreadLocal
(第四种情况)。这个问题的答案取决于ThreadLocal实现
将ThreadLocal视为一个容器
ThreadLocal
是一个在内部维护ThreadLocalMap
的容器,这ThreadLocalMap
是ThreadLocal需要保持静态的关键(虽然不是必需的,但建议保持静态)
因为我们希望每个类有一个容器
,而不是每个实例有一个容器
。如果我们每个实例有一个容器,我们将拥有和实例一样多的容器,这将造成内存泄漏。
这里有更多细节
您链接的问题的答案很好地解释了这一点。你还不明白什么?您是否了解,如果您有10个对象,每个对象都有一个ThreadLocal实例字段,那么您有10个不同的位置,其中一些状态可以与当前线程关联?你通常不希望这样。您通常想要的是类似“当前使用此线程的用户是John”或“与当前线程关联的事务就是该线程”的内容。从技术上讲,它不必是,但是你能说出一件你不希望它是静态的东西吗?@Voo:问题是我刚刚看到SpringSecurity ContextHolder类,其中身份验证对象保存在ThreadLocal变量中。所以要理解这一点,我需要理解ThreadLocal变量