ThreadLocal类

1,ThreadLocal与Thread

1)Thread类,拥有TheadLocalMap类型的成员变量,map操作被ThreadLocal类维护,不同线程操作的是自己的ThreadLocalMap,key是同一个ThreadLocal对象。

image.png

一个线程要保存多个变量,就需要创建多个ThreadLocal。
image.png

2)ThreadLocal类。ThreadLocalMap是ThreadLocal的静态内部类。
ThreadLocal有一个Entry数组。private Entry[] table;
Entry类中value属性用来保存和线程关联的具体对象,key是ThreadLocal类型
image.png

3)ThreadLocal类操作当前线程的ThreadLocalMap。

//保存value到当前线程
public void set(T value) {
        Thread t = Thread.currentThread();//得到当前线程
        ThreadLocalMap map = getMap(t);//得到当前线程的ThreadLocalMap对象。
        if (map != null)
        //每个线程set,key相同,因为参数this为ThreadLocal对象,只new了一个。
            map.set(this, value);//将自身对象作为key。
        else
            createMap(t, value);
}

//当第一次调用set方法时,会创建一个ThreadLocalMap对象。
void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
}

ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
}
//从当前线程的threadlocals中去除指定key对应的value
public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);//不同的线程使用相同的key来取值,得到的各自线程保存的对象。
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
        return setInitialValue();
    }

4)ThreadLocal内存处理
内存结构表示

image.png

ThreadLocalMap在get、set、remove时,会自动清理key为null的值,避免内存泄露
image.png

2,ThreadLocal应用

1)动态数据源

public class DynamicDataSourceHolder {

    private static final ThreadLocal<DynamicDataSourceGlobalEnum> holder = new ThreadLocal<DynamicDataSourceGlobal>();

    private DynamicDataSourceHolder() {
    }

    public static void putDataSource(DynamicDataSourceGlobalEnum dataSource){
        holder.set(dataSource);
    }

    public static DynamicDataSourceGlobal getDataSource(){
        return holder.get();
    }

    public static void clearDataSource() {
        holder.remove();
    }
}

//每个Controller中的请求,都会使用一个线程来处理。
//DynamicDataSourceHolder.putDataSource(DynamicDataSourceGlobalEnum.READ);
....业务逻辑
//DynamicDataSourceHolder.clearDataSource();业务逻辑完毕后,清除threadLocalMap中key为this的对象。
public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
                //获取当前线程的数据源类型
        return DynamicDataSourceHolder.getDataSource();
    }

}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容