ThreadLocal源码笔记
引言
总所周知,对Java多线程的共享资源的访问会产生竞争条件,为了保护临界区,往往需要加锁,使所有线程以串行的方式访问临界区,这是以牺牲时间性能为代价的。ThredLocal的实现机制是:为每一个线程分配一个副本,所有副本之间相互独立,互不影响,因此不会产生线程竞争,所有线程可以并行运行。这是以牺牲空间性能为代价的。
类图关系
如图所示:每一个线程类Thread中包含一个类型为ThreadLocalMap的threadLocals对象,该ThreadLocalMap包含一个table数组,数组元素为Entry。ThreadLocalMap是ThreadLocal的静态内部类,Entry是ThreadLocalMap的静态内部类,因此在ThreadLocalMap中可以拿到外部类ThreadLocal的引用,Entry的key即为该ThreadLocal的弱引用。ThreadLocal相当于一个Manager对相关Thread对象中的局部变量ThreadLocalMap进行操作。Entry的代码结构如下:
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
ThreadLocal关键方法
1. 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(t)方法获取ThreadLocalMap与该Thread t对应的ThreadLocalMap对象map,在map中可以以当前ThreadLocal实例this为key得到value。getMap为:
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
threadLocals为Thread类的局部变量,因此一个Thread对象对应一个ThreadLocalMap对象。如果map为null证明需要初始化Thread的ThreadLocalMap对象:
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
这里会给Thread的局部变量threadLocals初始化一个值,保证Thread对象唯一的ThreadLocalMap对象不为空。
2. get()方法
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
如果获取的Entry为空,则需给该map设置初值:
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;
}
protected T initialValue() {
return null;
}
参考:
1.ThreadLocal