ThreadLocal

79 阅读2分钟

1. ThreadLocalMap

功能:负责保存数据。
实现:由Entry[] 数组实现。根据ThreadLoal实例计算下标。
声明位置:在Thread中声明ThreadLocalMap类型的threadLocals实例变量。

public class Thread implements Runnable {
    ThreadLocal.ThreadLocalMap threadLocals;
}

2. ThreadLoal 是什么?

ThreadLocal实例是当前线程Thread中属性threadLocals的管理者。

3. ThreadLocal的原理

ThreadLocal实例的查询操作是 根据自身实例去当前线程Thread的threadLocals属性去查询。 新增、删除也是如此。

4. 使用场景

全局存储用户信息、解决线程安全问题

在Spring的Web项目中,我们通常会将业务分为Controller层,Service层,Dao层, 我们都知道 @Autowired注解默认使用单例模式 ,那么不同请求线程进来之后,由于Dao层使用单例,那么负责数据库连接的Connection也只有一个, 如果每个请求线程都去连接数据库,那么就会造成线程不安全的问题,Spring是如何解决这个问题的呢?

在Spring项目中Dao层中装配的Connection肯定是线程安全的,其解决方案就是采用ThreadLocal方法,当每个请求线程使用Connection的时候, 都会从ThreadLocal获取一次,如果为null,说明没有进行过数据库连接,连接后存入ThreadLocal中,如此一来,每一个请求线程都保存有一份自己的Connection。于是便解决了线程安全问题

5. ThreadLocal 内存泄漏

java.lang.ThreadLocal.ThreadLocalMap.Entrykey为弱引用。

static class Entry extends WeakReference<ThreadLocal<?>> {  
    /** The value associated with this ThreadLocal. */  
    Object value;  
    Entry(ThreadLocal<?> k, Object v) {  
        super(k);  
        value = v;  
    }  
}

ThreadLocal在没有外部强引用时,发生 GC 时会被回收,那么 ThreadLocalMap 中保存的 key 值就变成了 null。
而 Entry 又被 threadLocalMap 对象引用,threadLocalMap 对象又被 Thread 对象所引用,那么线程一直不结束,value对象则会一直存在于内存中,也就导致了内存泄漏,直至 Thread被销毁后,才会被回收。

6. ThreadLocal 如何避免内存泄漏

threadLocal.remove()
使用完ThreadLocal ,最好手动调用 remove() 方法,防止出现内存溢出。