ThreadLocal,线程本地化对象,在多线程环境中,使用ThreadLocal对象来维护变量时,ThreadLocal为每个使用该变量的线程维护一个独立的线程副本。
ThreadLocal.java源文件内容为:
/**
* ThreadLocal内部包含一个用数组实现的哈希表,用来存储对应到每个线程的局部对象的值
* 其中,ThreadLocal对象担当key,实际通过threadLocalHashCode值来进行检索
*/
public class ThreadLocal<T> {
//其中 T 类型代表的是被多个线程访问的局部变量类型
/**
* 在ThreadLocalMaps中用于产生哈希值
*/
private final int threadLocalHashCode = nextHashCode();
/**
* 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 <tt>initialValue</tt> 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}.
* * <p>This implementation simply returns <tt>null</tt>; if the
* programmer desires thread-local variables to have an initial
* value other than <tt>null</tt>, <tt>ThreadLocal</tt> 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() {
//protected成员,期望被子类继承
return null;
}
/**
* 返回在当前线程中的线程局部对象的值,
* 若线程局部对象对于当前线程没有值,则被初始化微 initialValue方法的返回值
*/
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();
}
/**
* 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 method to set the values of thread-locals.
*/
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
//以当前线程对象为key,设置当前局部对象的值
map.set(this, value);
else
createMap(t, value);
}
/**
* 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
* <tt>initialValue</tt> method in the current thread.
*/
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
//从ThreadLocalMap中移除对象
m.remove(this);
}
/**
* Get the map associated with a ThreadLocal. Overridden in
* InheritableThreadLocal.
* * @param t the current thread
* @return the map
*/
ThreadLocalMap getMap(Thread t) {
//返回当前Threadlocal相关的ThreadLocalMap对象
return t.threadLocals;
}
/**
* Create the map associated with a ThreadLocal. Overridden in
* InheritableThreadLocal.
* * @param t the current thread
* @param firstValue value for the initial entry of the map
* @param map the map to store.
*/
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue); //为当前线程创建关联的ThreadLocalMap对象
}
//ThreadLocalMap是一个定制的只能用来存储线程局部对象的哈希映射
//使用弱引用来当做key,只有当表空间不够时,旧的对象才会被移除
static class ThreadLocalMap {
//ThreadLocalMap的内部数组的元素类型:使用对ThreadLocal的弱引用类型来作为元素类型
static class Entry extends WeakReference<ThreadLocal> {
/**
* The value associated with this ThreadLocal.
*/
Object value;
Entry(ThreadLocal k, Object v) {
super(k);
value = v;
}
}
//哈希表的初始大小
private static final int INITIAL_CAPACITY = 16;
/**
* 用于存储ThreadLocal弱引用的数组
*/
private Entry[] table;
//ThreadLocalMap使用延迟初始化,当我们需要向ThreadLocalMap中放元素时,才会初始化它
ThreadLocalMap(ThreadLocal firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue); //初始时,使用ThreadLocal.threadLocalHashCode作为哈希表的哈希值 size = 1;
//设定ThreadLocalMap中元素个数
setThreshold(INITIAL_CAPACITY);
}
/**
* Set the value associated with key.
* * @param key the thread local object
* @param value the value to be 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);
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();
}
/**
* Remove the entry for 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使用一个ThreadLocalMap对象(内部通过数组和哈希来保存,以当前线程为键)来为每一个线程保存一份变量的本地化对象。