ThreadLocal是本地线程副本变量工具类。
用来存储值供线程使用。一般存储上下文对象。
用法:
public class ThreadLocalTest {
private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
publicstaticvoidmain(String[] args){
new Thread(() -> {
try {
for (int i = 0; i < 100; i++) {
threadLocal.set(i);
System.out.println(Thread.currentThread().getName() + "====" + threadLocal.get());
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} finally {
threadLocal.remove();
}
}, "threadLocal1").start();
new Thread(() -> {
try {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + "====" + threadLocal.get());
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
} finally {
threadLocal.remove();
}
}, "threadLocal2").start();
}
}
特性:每个线程都有独立的ThreadLocal,因为线程有ThreadLocalMap变量,实际上ThreadLocal存储的值是存在ThreadLocalMap中,是以ThreadLocal为key来存储值。在线程中能取到是因为ThreadLocal和Thread是在同一个包中,所以ThreadLocal可以通过取得当前Thread对象来获取ThreadLocalMap对象。
ThreadLocal只能对应一个Object,因为相当于他是以自身为key,key是唯一值。
阿里规范:
细节:ThreadLocal存储相当于ThreadLocalMap做为key来的,实现是定义了一个entry
entry是实现了虚引用的,虚引用在GC回收的时候会检测如果只有虚引用是会回收掉的,那么如果不作为static常量来定义ThreadLocal,ThreadLocal在只有entry的key指向的时候是会被回收掉的,而entry是强引用的,所有当ThreadLocalMap中key被回收掉变为null的时候value不会被回收掉,这样就会引起内存泄露,ThreadLocalMap有做处理,当每次get,set,remove时候会把key为null的给移除掉,但是如果后续没有任何操作依然会引起内存泄漏。这里代码贴出来是参考阿里最佳实践,做为static来声明,每次使用try finaly 来remove掉。
扩展:FastThreadLocal 吞吐速度是ThreadLocal的3倍左右