1,ThreadLocal与Thread
1)Thread类,
拥有TheadLocalMap类型的成员变量,map操作被ThreadLocal类维护,不同线程操作的是自己的ThreadLocalMap,key是同一个ThreadLocal对象。
一个线程要保存多个变量,就需要创建多个ThreadLocal。
2)ThreadLocal类。ThreadLocalMap是ThreadLocal的静态内部类。
ThreadLocal有一个Entry数组。private Entry[] table;
Entry类中value属性用来保存和线程关联的具体对象,key是ThreadLocal类型
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内存处理
内存结构表示
ThreadLocalMap在get、set、remove时,会自动清理key为null的值,避免内存泄露
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();
}
}