这一章节我们来讨论一下ThreadLocal的实现原理。
一般可以认为是ThreadLocalMap这个内部类来存储,但是如果更加深入一层,其实他的存储是Entry类的可变数组,这个跟HashMap的存储比较相似
ThreadLocal的初始化源码:
/**
* Returns the current thread's "initial value" for this
* thread-local variable. This method will be invoked the first
* time a thread accesses the variable with the {@link #get}
* method, unless the thread previously invoked the {@link #set}
* method, in which case the initialValue method will not
* be invoked for the thread. Normally, this method is invoked at
* most once per thread, but it may be invoked again in case of
* subsequent invocations of {@link #remove} followed by {@link #get}.
*
* This implementation simply returns null; if the
* programmer desires thread-local variables to have an initial
* value other than null, ThreadLocal must be
* subclassed, and this method overridden. Typically, an
* anonymous inner class will be used.
*
* @return the initial value for this thread-local
*/
protected T initialValue() {
return null;
}
其实我们一打开源码就不难看见,其实在初始化之初,直接就是返回null,所以在没有初始化的情况下,直接get里面的元素,是返回null
源码:
/**
* Sets the current thread's copy of this thread-local variable
* to the specified value. Most subclasses will have no need to
* override this method, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
*
* @param value the value to be stored in the current thread's copy of
* this thread-local.
*/
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作为容器,然后把值放到里面去,我们在进入ThreadLocalMap去看看
ThreadLocalMap是在ThreadLocal里面实现的内部类,由于代码太长这里就不贴出来,笔者曾看到有文章说ThreadLocalMap跟HashMap的实现是一样,然后仔细对比ThreadLocalMap跟HashMap的实现,是非常的相似,都是使用Entry数组来实现存储,然后遍历里面的元素,估计当时设计的思路都差不多,但是HashMap在Entry的实现上,明显比ThreadLocalMap的Entry要强。
源码:
/**
* Returns the value in the current thread's copy of this
* thread-local variable. If the variable has no value for the
* current thread, it is first initialized to the value returned
* by an invocation of the {@link #initialValue} method.
*
* @return the current thread's value of this thread-local
*/
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null)
return (T)e.value;
}
return setInitialValue();
}
讲到get方法,我们深入debug,发现:
我们点击进去setInitialValue方法,
/**
* Variant of set() to establish initialValue. Used instead
* of set() in case user has overridden the set() method.
*
* @return the initial value
*/
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;
}
可以看到他返回的是value,而value,也就是初始化方法initialValue()的返回值,这里就解释了为什么没有初始化的时候,get返回的是null
我们分别看看set和get方法里面的某一两句
set方法
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
get方法
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
getMap方法
/**
* Get the map associated with a ThreadLocal. Overridden in
* InheritableThreadLocal.
*
* @param t the current thread
* @return the map
*/
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
在两个方法里面,一开始都会出现这两句代码,这里我们点击去getmap方法,看见,里面出现了t.threadLocals,使用变量副本的原因就在这一句里面。
源码:
/**
* Removes the current thread's value for this thread-local
* variable. If this thread-local variable is subsequently
* {@linkplain #get read} by the current thread, its value will be
* reinitialized by invoking its {@link #initialValue} method,
* unless its value is {@linkplain #set set} by the current thread
* in the interim. This may result in multiple invocations of the
* initialValue method in the current thread.
*
* @since 1.5
*/
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
remove方法主要是去掉某个线程的变量副本,使得这个线程不能够在使用变量副本进行计算。
总结:我们这一章节简单的描述了ThreadLocal的实现原理。
这一章节就到这里,谢谢。
我的github:https://github.com/raylee2015/DeepIntoThread
目录:http://blog.csdn.net/raylee2007/article/details/51204573