1、ThreadLocal
的简单使用
ThreadLocal tl = new ThreadLocal();
tl.set(T); //设值
t1.get();
2、原理分析
先看一下ThreadLocal
的set(T value)
方法的源码
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
getMap(Thread t)
方法源码:
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
总结1:从上代码我们可以查出ThreadLocal
的set
方法保存的值,最终是保存在当前线程的ThreadLocal.ThreadLocalMap
类的threadLocals
属性中的。
继续往下看:
createMap(t,value)
源码:
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
//ThreadLocal.ThreadLocalMap
private Entry[] table;
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
ThreadLocalMap
的set
方法源码:
private void set(ThreadLocal<?> key, Object value) {
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();
}
结论2:ThreadLocal
的set
方法保存的值最终是保证在ThreadLocal.ThreadLocalMap
的Entity[] table
属性中,并且是以this
即当前ThreadLocal
的Hash Code取模得出其在table
数组中的下标index,同时存储的Entity的key是当前ThreadLocal
为key,value是待存放的对象。
总结:
set方法总结:
ThreadLocal
的set
方法是将key=当前ThreadLocal
对象,value=待存放对象的Entity元素存放于当前线程对象的ThreadLocal.ThreadLocalMap
类型的 threadLocals
属性的Entity[] table
属性中。同时是以当前ThreadLocal
的Hash Code取模得出其在table中下标值。
ThreadLocal
之所以能隔离线程本地变量的原理:
1)对于某一确定ThreadLocal
对象来讲,它对应的索引值i是确定的,在不同线程之间访问时访问的是不同的table数组的同一位置即都为table[i],只不过这个不同线程之间的table是独立的。
2)对于同一线程的不同ThreadLocal
来讲,这些ThreadLocal
实例共享一个table数组,然后每个ThreadLocal
实例在table中的索引i是不同的。
再来看看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方法的知识,get方法就比较容易理解了!