场景
调用第三方的接口,有很多个,每个接口参数都要传token或者用户id,每个方法都要定义参数,显然过于繁琐,所以想到用ThreadLocal来实现,但是发现知识点忘了很多,所以看看别人的文章整理下,以后随时补充新的知识点。
用法
声明一个变量,然后在某个地方进行set相关值后,在某个地方进行获取
它是如何保证每个线程相互不影响值呢
set值的时候,是从当前线程对象中获取threadLocals属性,类似map,然后往里放value ,key就是this即我们new出来的那个ThreadLocal对象,所以threadlocalMap是属于各自线程的成员属性,所以不影响,同时也不需要用锁之类
声明threadLocal变量为静态成员变量原因
从源码中可以看出,threadlocalMap是在各自的线程里面的维护的,所以不存在冲突和竞争关系,那么threadLocal变量就没必要声明为局部变量,造成空间的浪费了,所以往往声明为静态变量,提高内存利用率
ThreadLocalMap的key是弱引用的目的
从源码中可以看出threadLocalMap的key是弱引用,弱引用???啥是弱引用,弱引用是啥??
度娘了解一番:
- 当你new出来的对象,在没有任何强引用连接它的时候,没有任何强悍的东西,而且此时只有弱引用,那么这个对象在下一次GC来临之前就会被回收掉,如果这个对象此时连弱引用都么有,那么它肯定也会被回收掉。
**所以弱引用是一个不足以强迫对象保留在内存中的引用,不影响垃圾收集器回收对象**
- 软引用呢,它比弱引用强悍一点,它引用的对象,如果内存充足,就一直存在,如果内存吃紧,那么就会回收它;会尽可能长的保留引用直到 JVM 内存不足时才会被回收,仅此而已的区别
- 重点来了:所以当threadLocal对象没有强引用指向他的时候即threadLocal=null这样;那么threadLocalMap中的key就只剩下弱引用了,那么下次GC来的时候,就会回收掉threadLocal实例对象;
key就变成了null;**所以弱引用的使用目的就是为了回收掉threadLocalMap中的key,这样当线程结束的时候,就全部都释放了,value也没人引用了**
,,但是我们常规开发下,threadLocal对象一般都是static修饰,意味着它的生命周期就延长很多了,所以此时弱引用其实意义没那么大了 - 重点的重点:如果此时线程使用的是线程池,那么即使你的threadLocal实例对象不是静态变量方式声明,作为局部变量声明,threadLocal对象为null的时候,但是线程却没有结束生命周期,那么threadLocalMap中的Entry对象就一直引用着那个value对象,导致这个value没有被回收掉,因为线程没结束啊,那就一直引用Entry对象,所以Entry里面的value就一直被引用无法回收,这种情况,线程一旦多起来,就内存泄露报错了,这个可能就是传说中内存泄露的情况,所以要想个办法,当key为null的时候,将value也变成null,这样就能回收对象了;
所以在使用threadLocal变量set之后,记得在finally下进行threadLocal.remove下,还有在全局异常处理的时候也记得remove
- 贴张图,加深下上面的理解
这篇博客写着也不错,点我