线程本地变量,就是每个线程都有同一个变量的独有拷贝,下面看看其基本实现原理。
其中常用的就是set/get方法了。set方法的代码为:
public void set(T value){
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if(map!=null)
map.set(this.value);
else
createMap(t,value);
}
//它调用了getMap,getMap的代码为:
ThreadLocalMap getMap(Thread t){
return t.threadLocals;
}
返回线程的实例变量threadLocals,它的初始值为null,在null时,set调用createMap初始化,代码为:
void createMap(Thread t, T firstValue){
t.threadLocals = new ThreadLocalMap(this,firstValue);
}
从上面代码可以看出,每个线程都有一个Map,类型为ThreadLocalMap,调用set实际上是在线程自己的Map里设置了一个条目,键为当前的ThreadLocal对象,值为value。ThreadLocalMap是一个内部类,它是专门用于ThreadLocal的,与一般的Map不同,它的键类型为WeakReference,它与Java的垃圾回收机制有关,使用它,便于回收内存。
get方法的代码为:
public T get(){
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if(map!=null){
ThreadLocalMap.Entry e = map.getEntry(this);
if(e!=null)
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
通过线程访问到Map,以ThreadLocal对象为键从Map中获取到条目,取其value,如果Map中没有,则调用setInitialValue,代码为:
private T setInitialValue(){
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if(map!=null)
map.set(this,value);
else
createMap(t,value);
return value;
}
initialValue()就是提供初始值的方法,默认实现就是返回null。
remove方法的代码如下。
public void remove(){
ThreadLocalMap m = getMap(Thread.currentThread());
if(m!=null)
m.remove(this);
}
}
通过获得当前线程,如果不为空,则调用map的remove方法删除。
总结下,每个线程都有一个Map,对于每个ThreadLocal对象,调用其get/set实际上就是以ThreadLocal对象为键读写当前线程的Map,这样,就实现了每个线程都有自己的独立副本的效果。1
使用场景:日期处理、随机数和上下文信息。
Java编程的逻辑 ↩︎