final ThreadLocal threadLocal = new ThreadLocal<>();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
//threadLocal.set("11");
System.out.println(Thread.currentThread().getName()+"@"+threadLocal.get());
}
},"thread1");
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
threadLocal.set("22");
System.out.println(Thread.currentThread().getName()+"@"+threadLocal.get());
}
},"thread2");
thread2.start();
thread1.start();
运行结果---------------------
thread1@null
thread2@22
从源码分析原因:
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
从set方法中,可以明确看出,每个thread 一定维护一个ThreadLocalMap map ;因为getMap方法是根据当前线程对象返回的;接下来看creatMap方法;
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
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);
}
在createMap方法中,每个thread维护一个threadLocals属性;其中的this,指向ThreadLocal 对象引用; 而ThreadLocalMap是在ThreadLocal 内部维护的内部类;因此当 指向threadLocal.set("22") 时,先判断当前线程对象的threadLocals存不存在,不存在直接调用createMap 方法,将threadLocal当做ThreadLocalMap 的key,value 当做ThreadLocalMap 的value值,封装一个对象数组;
static class Entry extends WeakReference {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal k, Object v) {
super(k);
value = v;
}
}
由于threadLocal 作为弱引用key,因此在get方法调用完成后,及时调用remove方法,GC掉ThreadLocalMap 对象,否则容易造成内存泄漏;
接着从get方法理解为什么thread1 线程对象调用threadLocal.get()方法获取到值为null;因为在代码执行到ThreadLocalMap map = getMap(t);这一行ThreadLocalMap map 对象为空;直接走到setInitialValue();方法;而该方法会创建一个ThreadLocalMap 对象,而默认的value值为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();
}
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);
}
protected T initialValue() {
return null;
}
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;
}