首先加深印象:
1.ThreadLocal解决的是每个线程需要有自己独立的实例,且这个实例的修改不会影响到其他线程。
这个ThreadLocal的用法一般都是创建各自线程自己运行过程中单独创建的对象的,不适合的相同实例共享的。
https://ask.csdn.net/questions/764337
ThreadLocal存入的对象就不该是同一个。这玩意不保证线程安全。
所谓的副本是指,A线程存入的值,对B线程并不感知,B只能拿到自己存的值,并不能拿到A存入的值。
因为一般情况下ThreadLocal 都是定义为static类型的,如果没有ThreadLocal,那么B线程就可以获取A线程所存入的值。
理解了使用场景,很多地方就能想通了
java ThreadLocal(应用场景及使用方式及原理)
2.ThreadLocal造成内存泄漏的问题我认为有两点:
1.key为弱引用,gc之后key为null,导致value无法被获取到
2.ThreadLocalMap的生命周期与Thread相同,导致内存泄漏一直存在
ThreadLocal原理总结
1.每个Thread维护着一个ThreadLocalMap的引用
![](https://img.haomeiwen.com/i20237768/a8f273bc71aba08d.png)
2.ThreadLocalMap是ThreadLocal的内部类,用Entry来进行存储
![](https://img.haomeiwen.com/i20237768/529410f611c25f9e.png)
3.调用ThreadLocal的set()方法时,实际上就是往ThreadLocalMap设置值,key是ThreadLocal对象,值是传递进来的对象
![](https://img.haomeiwen.com/i20237768/d0cb2de4fc7e61d3.png)
4.调用ThreadLocal的get()方法时,实际上就是往ThreadLocalMap获取值,key是ThreadLocal对象
![](https://img.haomeiwen.com/i20237768/76f30fe0e7d0caf8.png)
5.ThreadLocal本身并不存储值,它只是作为一个key来让线程从ThreadLocalMap获取value。
![](https://img.haomeiwen.com/i20237768/5fc79c3c0157d12b.png)
这里放出一个程序可以思考一下会输出什么?
public class A {
public static ThreadLocal local = new ThreadLocal();
public static ThreadLocal local2 = new ThreadLocal();
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
int i;
local.set(1);
local2.set(2);
System.out.println(local.get());
local2.set(3);
System.out.println(local2.get());
}
}).start();
}
}
答案是
1
3
可以debug来看一下他的流程
![](https://img.haomeiwen.com/i20237768/d2b63d6303c0c2fa.png)
第一次set,由于Thread中的map还没有被初始化,所以先创建map
![](https://img.haomeiwen.com/i20237768/4228d997b334a129.png)
此时到了第二个TheadLocal对象
![](https://img.haomeiwen.com/i20237768/aa32862e16b966b3.png)
因为第一个ThreadLocal已经初始化了map,所以map!=null为true,
![](https://img.haomeiwen.com/i20237768/c5999eb74b8d0d73.png)
进入到get方法,发现map的Entry中已经存了两个对象了,可以明确看到不同的ThreadLocal对象存储也是不会互相影响的,如果一个ThreadLocal要对应多个value的话,最好把value封装成一个对象。
![](https://img.haomeiwen.com/i20237768/c58b5f1c2d9e80e8.png)
到此为止,上面的程序也好理解了,
//先对map进行了初始化,并且把local作为key,1作为value存到map的entry当中
1 local.set(1);
//获取到Thread中的ThreadLocalMap,此时map已经初始化过了,直接把local2作为key,2作为value存到map的entry当中
2 local2.set(2);
//注意这里是local.get(),取到的是local对象对应的entry,所以得到1。
3 System.out.println(local.get());
![](https://img.haomeiwen.com/i20237768/1f0483d513b54653.png)
网友评论