java.lang.ThreadLocal的作用
ThreadLocal可以保证当前拿到的变量是属于当前访问的线程。也就是每个线程自己的独立小空间。实现了线程之间的数据隔离。
例子
public class ThreadLocalTest {
private static ThreadLocal<String> tl = new ThreadLocal<String>();
public static void main(String[] args) {
tl.set("哈哈");
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ":" + tl.get());
}
}).start();
System.out.println(Thread.currentThread().getName() + ":" + tl.get());
}
}
运行结果:
解释:
虽然主线程main往ThreadLocal里面设置了值并且其也可以拿到值,但是线程Thread-0却没有拿到值,可以看出线程之间的数据隔离。
源码分析
set方法
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
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);
}
解释:
① 获取当前线程对应的map,如果map不为空,就将值设置到map中。如果map为空就将创建Map结构,然后将值放入到链表中。
注意:可以发现ThreadLocalMap的构造器采用HashMap的套路,初始化节点数组,然后使用键key进行按位与运算计算数组下标,设置最大临界值为初始化容量。
get方法
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 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;
}
解释:
① 首先获取当前线程的本地map映射。
② 如果map不为空,那么就走Hashmap的套路,通过键按位与运算计算下标,然后通过下标获取值。
③ 否则会再判断下map是否为空,如果空就创建下ThreadLocalMap,但是最后的效果就是拿到初始化传入的值,初始化传入的值就是null,除非自己重写initialValue方法。
ThreadLocal的应用场景:
每一个线程都有一个自己的对象,并且可以很多处用到,放到ThreadLocal中便于存取。