ThreadLocal类

1,ThreadLocal与Thread

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

image.png

一个线程要保存多个变量,就需要创建多个ThreadLocal。
ThreadLocal类_第1张图片
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内存处理
内存结构表示

ThreadLocal类_第2张图片
image.png

ThreadLocalMap在get、set、remove时,会自动清理key为null的值,避免内存泄露
ThreadLocal类_第3张图片
image.png

2,ThreadLocal应用

1)动态数据源

public class DynamicDataSourceHolder {

    private static final ThreadLocal holder = new ThreadLocal();

    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();
    }

}

你可能感兴趣的:(ThreadLocal类)