ThreadLocal
1.ThreadLocal是什么
ThreadLocal 是一个创建线程局部变量的类
通常我们创建的变量是可以被任何一个线程访问的,而使用 ThreadLocal 创建的变量只能被当前线程访问,其他线程无法访问。
2.ThreadLocal是如何确保只有当前线程可以访问
我们先来分析一下ThreadLocal里面最重要的两个函数,get()
,set()
两个函数。
public T get() {
//获取当前线程
Thread t = Thread.currentThread();
//利用当前线程t来获取当前线程中的 threadLocals 变量
ThreadLocalMap map = getMap(t);
if (map != null) {
//利用当前threadlocal作为key来获取 ThreadLocalMap.Entry,其中就有保存的value
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
从get()
,set()
两个函数,不难发现,在给ThreadLocal去set值或者get值的时候都会先获取当前线程,然后使用线程去调用getMap(thread)
,getMap
返回的就是线程thread的成员变量threadLocals
。所以这样就保证了threadLocal的访问,一定是只能访问或修改当前线程的值,这就保障了这个变量是线程的局部变量。
ThreadLocal.png
ThreadLocalMap是什么
ThreadLocalMap是ThreadLocal的内部类。
static class ThreadLocalMap {
/**
* The entries in this hash map extend WeakReference, using
* its main ref field as the key (which is always a
* ThreadLocal object). Note that null keys (i.e. entry.get()
* == null) mean that the key is no longer referenced, so the
* entry can be expunged from table. Such entries are referred to
* as "stale entries" in the code that follows.
*/
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
private Entry[] table;
}
从源码可以看出来ThreadLocalMap中有一个数组table,数组里面是继承自弱引用的Entry。弱引用的使用也是为了当出现异常情况,比如死循环的时候内存能得到回收。Entry里面就保存了真实的白娘value,并且以threadlocal作为key。所以相同类型的threadLocal只能在线程中关联一个实例。