本文最后更新于48 天前,其中的信息可能已经过时,如有错误请发送邮件到big_fw@foxmail.com
ThreadLocal叫线程变量,底层是在线程里维护了一个map(ThreadLocalMap),map的key是ThreadLocal,value未任意对象的存储结构。
当一个Key-Value值被存储后,会一直附带在线程上,也就是说,可以在线程运行的任何位置通过这个ThreadLocal对象设定或取到存入的值。
public class Main {
private static class PrintTime {
// 这里创建了一个ThreadLocal对象,叫做TIME_THREADLOCAL_OBJECT
private static final ThreadLocal<Long> TIME_THREADLOCAL_OBJECT = new ThreadLocal<>();
//private static final ThreadLocal<Object> another_threadlocal_object = new ThreadLocal<>();
public static final void begin(){
// set方法只需要传value值,无需传key, 是因为TIME_THREADLOCAL_OBJECT对象会作为key
TIME_THREADLOCAL_OBJECT.set(System.currentTimeMillis());
}
public static final long end(){
// get方法无需传key, 是因为TIME_THREADLOCAL_OBJECT对象会作为key
return System.currentTimeMillis()-TIME_THREADLOCAL_OBJECT.get();
}
}
public static void main(String[] args) throws InterruptedException {
PrintTime.begin();
TimeUnit.SECONDS.sleep(2);
long time = PrintTime.end();
System.out.println(time+"毫秒");
}
}
这里创建了一个ThreadLoacl对象,叫做TIME_THREADLOCAL_OBJECT,可以理解为这个对象本身就作为一个key,存储一个数据类型为long的value值,到线程的ThreadLocalMap中。
使用ThreadLocal导致的内存泄露问题:
ThreadLoaclMap中的key为ThreadLocal的弱引用,value为强引用,。如果ThreadLocal对象没有被外部强引用,垃圾回收时就会将key清除,但value没有被清除,这时不做处理,value将永远不会被GC清除掉,此时可能发生内存泄漏。ThreadLocalMap的实现考虑了这个问题,在调用get/set/remove时会清理掉key为null的entry。但是可能编程没有用到这些方法,所以最好在编程的时候意识到这里编写的run方法里不会再使用ThreadLocal对象了,最好手动调用remove