源码中对于ThreadLocal类的解释是:
/**
* This class provides thread-local variables. These variables differ from
* their normal counterparts in that each thread that accesses one (via its
* {@code get} or {@code set} method) has its own, independently initialized
* copy of the variable. {@code ThreadLocal} instances are typically private
* static fields in classes that wish to associate state with a thread (e.g.,
* a user ID or Transaction ID).
*/
//几个静态常量
private final int threadLocalHashCode = nextHashCode();
private static AtomicInteger nextHashCode = new AtomicInteger();
private static final int HASH_INCREMENT = 0x61c88647;
从上面的官方解释中我们可以得出三点
从表面看,ThreadLocal可以理解为一个Map对象,当前线程作为key,需要存储的对象作为value,可仔细研究过源码后,ThreadLocal本质是通过它的静态内部类ThreadLocalMap来为每个线程维护一个数组table,即Entryp[],当前线程的threadLocalHashCode值作为数组下标。
稍后介绍ThreadLocal的添加(set(T value))、获取(get())、删除(remove())等方法的实现,看完这篇介绍,就会理解ThreadLocal的实现方式,不怕被面试官吊打了。
添加实现set(T value)
public void set(T value) {
//获取当前线程Thread
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
//获取ThreadLocalMap
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
//创建ThreadLocalMap
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
通过阅读源码,可以知道ThreadLocal的set方法主要分为以下几个步骤
删除remove()实现
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
ThreadLocal的remove方法比较简单,就是通过当前Thread对象获取到ThreadLocalMap对象,如果不为null的话,调用ThreadLocalMap的remove方法实现。
获取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();
}
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;
}
通过阅读源码,可以知道ThreadLocal的get方法主要分为以下几个步骤
简要介绍下ThreadLocalMap
ThreadLocalMap仅用于维护线程本地值的Map,仅作为ThreadLocal的私有静态内部类。
//默认的table容量
private static final int INITIAL_CAPACITY = 16;
//Entry数组,创建ThreadLocalMap的时候会创建一个默认容量的table数组
private Entry[] table;
//当前Entry的长度
private int size = 0;
//下一个要调整大小的值
private int threshold; // Default to 0
上面的四个常量,记录着ThreadLocalMap的状态变化。
ThreadLocalMap.set(ThreadLocal> key, Object value)
//添加具体实现,该方法为ThreadLocalMap的方法
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数组
Entry[] tab = table;
int len = tab.length;
//获取索引
int i = key.threadLocalHashCode & (len-1);
//遍历tab,如果存在直接更新
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;
//满足条件数组扩容x2
if (!cleanSomeSlots(i, sz) && sz >= threshold)
rehash();
}
该方法是ThreadLocal的set(T value)的具体实现,通过阅读源码可以知道set(ThreadLocal> key, Object value)的实现具体分为以下几个步骤
ThreadLocalMap.getEntry(ThreadLocal> key)
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);
}
private Entry getEntryAfterMiss(ThreadLocal> key, int i, Entry e) {
Entry[] tab = table;
int len = tab.length;
while (e != null) {
ThreadLocal> k = e.get();
if (k == key)
return e;
if (k == null)
expungeStaleEntry(i);
else
i = nextIndex(i, len);
e = tab[i];
}
return null;
}
该方法是ThreadLocal的get()的具体实现,通过阅读源码后可以知道具体实现步骤
ThreadLocalMap.remove(ThreadLocal> key)
private void remove(ThreadLocal> key) {
Entry[] tab = table;
int len = tab.length;
int i = key.threadLocalHashCode & (len-1);
for (Entry e = tab[i];
e != null;
e = tab[i = nextIndex(i, len)]) {
if (e.get() == key) {
e.clear();
expungeStaleEntry(i);
return;
}
}
}
该方法是ThreadLocal的remove()的具体实现,通过阅读源码后可以知道具体实现步骤
扩展:ThreadLocalMap和Synchronized