ThreadLocal提供了一个线程独立的变量。在不同线程中调set,get设置的值都是和该线程相关的。网上对ThreadLocal的实现众说纷纭,今天来看下源码。基于JDK1.8。
支持原创,转载请注明出处。
类图
ThreadLocal.set方法
public void set(T value) {
Thread t = Thread.currentThread(); //获取当前线程对象
ThreadLocalMap map = getMap(t); //获取ThreadLocalMap对象
if (map != null)
map.set(this, value); //调用ThreadLocalMap的set方法
else
createMap(t, value);
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals; //返回Thread的ThreadLocalMap成员变量
}
ThreadLocal.ThreadLocalMap threadLocals = null; //Thread的ThreadLocalMap成员
该方法获取当前线程的Thread对象中的trheadLocal成员变量,调用它的set方法。
ThreadLocalMap.set方法
private void set(ThreadLocal<?> key, Object value) {
// We don't use a fast path as with get() because it is at
// least as common to use set() to create new entries as
// it is to replace existing ones, in which case, a fast
// path would fail more often than not.
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1); //通过hash值,计算下标
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) { //不断获取下一个下标直到某个槽没有元素
ThreadLocal<?> k = e.get();
if (k == key) {
e.value = value;
return;
}
if (k == null) {
replaceStaleEntry(key, value, i);
return;
}
}
tab[i] = new Entry(key, value); //将该元素加入这个槽
int sz = ++size;
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
我们看下Entry这个类:
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
这个类继承自WeakReference,所以只要ThreadLocal对象存在,那么设置在里面的值就不会被回收。我们看下get方法。
ThreadLocal.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();
}
和set方法类似。我们看下map.getEntry方法:
private Entry getEntry(ThreadLocal<?> key) {
int i = key.threadLocalHashCode & (table.length - 1); //计算下标
Entry e = table[i];
if (e != null && e.get() == key)
return e;
else
return getEntryAfterMiss(key, i, e);
}
和set方法类似,一看就明白了。
总结
我们最后回顾下类图:
支持原创,转载请注明出处。
github:https://github.com/gatsbydhn