ThreadLocal详解
一、ThreadLocal简介
ThreadLocal叫做线程变量,意思是ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的,也就是说该变量是当前线程独有的变量。ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。
ThreadLocal 提供了线程本地的实例。它与普通变量的区别在于,每个使用该变量的线程都会初始化一个完全独立的实例副本。ThreadLocal 变量通常被static final修饰。当一个线程结束时,它所使用的所有 ThreadLocal 相对的实例副本都可被回收。
二、ThreadLocal与Synchronized的区别
1、Synchronized用于线程间的数据共享,而ThreadLocal则用于线程间的数据隔离。
2、Synchronized是利用锁的机制,使变量或代码块在某一时该只能被一个线程访问。而ThreadLocal为每一个线程都提供了变量的副本。
三、ThreadLocal的简单使用
1 | public class ThreadLocaDemo { |
从这个示例中我们可以看到,两个线程分表获取了自己线程存放的变量,他们之间变量的获取并不会错乱。
四、ThreadLocal的原理
1.ThreadLocal的set()方法:
1 | public void set(T value) { |
那么ThreadLocalMap又是什么呢?
下面只是部分源码
1 | static class ThreadLocalMap { |
根据源码可看出ThreadLocalMap是ThreadLocal的内部静态类,而它的构成主要是用Entry来保存数据 ,而且还是继承的弱引用。在Entry内部使用ThreadLocal作为key,使用我们设置的value作为value。
2.ThreadLocal的get方法
1 | public T get() { |
3、ThreadLocal的数据结构
五、常见使用场景
1.存储用户Session
2.Spring使用ThreadLocal解决线程安全问题
六、ThreadLocal 内存泄露问题是怎么导致的?
ThreadLocalMap
中使用的 key 为 ThreadLocal
的弱引用,而 value 是强引用。所以,如果 ThreadLocal
没有被外部强引用的情况下,在垃圾回收的时候,key 会被清理掉,而 value 不会被清理掉。
这样一来,ThreadLocalMap
中就会出现 key 为 null 的 Entry。假如我们不做任何措施的话,value 永远无法被 GC 回收,这个时候就可能会产生内存泄露。ThreadLocalMap
实现中已经考虑了这种情况,在调用 set()
、get()
、remove()
方法的时候,会清理掉 key 为 null 的记录。使用完 ThreadLocal
方法后 最好手动调用remove()
方法。