首先加深印象:
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的引用

2.ThreadLocalMap是ThreadLocal的内部类,用Entry来进行存储

3.调用ThreadLocal的set()方法时,实际上就是往ThreadLocalMap设置值,key是ThreadLocal对象,值是传递进来的对象

4.调用ThreadLocal的get()方法时,实际上就是往ThreadLocalMap获取值,key是ThreadLocal对象

5.ThreadLocal本身并不存储值,它只是作为一个key来让线程从ThreadLocalMap获取value。

这里放出一个程序可以思考一下会输出什么?
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来看一下他的流程

第一次set,由于Thread中的map还没有被初始化,所以先创建map

此时到了第二个TheadLocal对象

因为第一个ThreadLocal已经初始化了map,所以map!=null为true,

进入到get方法,发现map的Entry中已经存了两个对象了,可以明确看到不同的ThreadLocal对象存储也是不会互相影响的,如果一个ThreadLocal要对应多个value的话,最好把value封装成一个对象。

到此为止,上面的程序也好理解了,
//先对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());

网友评论