ThreadLocal是一个用于将对象线程封闭的类,每个线程都能访问到相互隔离的对象副本,这样访问这个对象就一定是线程安全的。大概原理就是HashMap<Thread,Object>,但是具体实现的差异还是很大的。之前因为理解偏差,看了源码半天没搞懂,看了网上的源码分析反而更是一头雾水,昨晚仔细看了一下,总算是明白了。
我看的是23的sdk的源码,这个版本的sdk的ThreadLocal跟Oracle提供的那个JDK里面的实现还是有差异的。JDK里面的ThreadLocal里面的静态类是一个Map,而ThreadLocal里面的静态类则不是Map。先不说细节,上一张图:
ThreadLocal有个静态类叫Values,Values内部有个数组,起到类似HashMap的作用。这个数组的第i位放ThreadLocal的弱引用,第i+1位则用来放值。 第i位是如何确定的呢,通过ThreadLocal的hash值,这个hash值又是通过hashCounter得到的:
注意到这里TheradLocal是key,而非Thread,映射关系也并非保存在ThreadLocal中,而是保存在每个Thread中。ThreadLocal所关心的仅仅是自己的hash值和弱引用。Thread内部保存着这个内部类的引用:
看看ThreadLocal的get()方法:
@SuppressWarnings("unchecked")
public T get() {//假如一个新线程去访问主线程里创建的threadlocal.get()
// Optimized for the fast path.
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);//看看自己保存的Values引用
if (values != null) { //不为空,则可以根据ThreadLocal的hash值去找到对应的值了
Object[] table = values.table;
int index = hash & values.mask;
if (this.reference == table[index]) {//key为弱引用
return (T) table[index + 1];//返回value
}
} else { //线程保存的hash数组为null ,那么要初始化这个hash数组
values = initializeValues(currentThread);
}
return (T) values.getAfterMiss(this);
}
ThreadLocal的set()方法:
public void set(T value) {//要为这个线程的对象副本赋值了
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values == null) {//本线程的hash数组未初始化
values = initializeValues(currentThread);
}
values.put(this, value);//放入
}
Values静态类里面的逻辑略复杂一点,我先不分析了。其实ThreadLocal的源码还是相对简单的,我昨晚看了那么久主要还是理解错了,一开始以为一定有一个Map保存在ThreadLocal内部,结果看了半天越看越糊涂。。。