java.lang.ThreadLocal
threadLocal 类型的本地变量存放在具体的线程内存空间中 。 ThreadLocal 就是一个工具壳,它通过 set 方法把 value 值放入调用线程的 threadLocals 里面并存放起来 , 当调用 线程调用它的 get 方法时,再从当 前线程的 threadLocals 变量里面将其拿出来使用 。 如果调用线程一直不终止, 那么这个本地
变量会一直存放在调用线程的 threadLocals 变量里面 ,所以当不需要使用本地变量时可以
通过调用 ThreadLocal 变量的 remove 方法 ,从当前线程的 threadLocals 里面删除该本地变量 。
另外, Thread 里面 的 threadLocals 为何被设计为 map 结构?很明显是因为每个线程可以关
联多个 ThreadLocal 变量 .
set 方法
public void set(T value) {
//1.获取当前线程
Thread t = Thread.currentThread();
//2.将当前线程作为 key ,去查找对应的线手呈交量,找到则设置
ThreadLocalMap map = getMap(t);
if (map != null)
// this就是当前的threadLocal
map.set(this, value);
else
//( 3 )第 一次调用就创建当前线程对应的 HashMap
createMap(t, value);
}
-
getMap方法
ThreadLocalMap getMap(Thread t) { //ThreadLocal.ThreadLocalMap threadLocals = null; return t.threadLocals; }
getMap(t)的作用是获取线程 自己的变量 threadLocal s, threadlocal 变量被
绑定到了线程的成员变量上
- createMap 方法
void createMap(Thread t, T firstValue) {
//创建Map对象,
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
get方法
public T get() {
//1.获取当前线程
Thread t = Thread.currentThread();
//2.将获取当前线程的 threadLocals 变量
ThreadLocalMap map = getMap(t);
//3. 如果threadLocals不为 null ,则返回对应本地变量的值
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
//4.threadLocals 为空则初始化当前线程的 threadLocals成员交量
return setInitialValue();
}
- setInitialValue 方法
private T setInitialValue() {
// 初始化 null
T value = initialValue();
//获取当前线程
Thread t = Thread.currentThread();
//获取当前线程的 threadLocals成员变量
ThreadLocalMap map = getMap(t);
if (map != null)
//设置值为null
map.set(this, value);
else
// 创建
createMap(t, value);
return value;
}
- initialValue
protected T initialValue() {
// 返回空
return null;
}
remove方法
public void remove() {
//当前线程的 threadLocals 变量
ThreadLocalMap m = getMap(Thread.currentThread());
//如果不为空就删除
if (m != null)
m.remove(this);
}
Threadlocal 不支持继承性
package com.ghgcn.threadstudy.lesson01;
/**
* @author 刘楠
* @since 2019/7/1
*/
public class TestThreadLocal01 {
private static ThreadLocal<String> threadLocal = new ThreadLocal<>();
public static void main(String[] args) {
threadLocal.set("abc");
Thread thread = new Thread(()->{
System.out.println(Thread.currentThread().getName()+" : "+threadLocal.get());
});
thread.start();
System.out.println("main : "+threadLocal.get());
}
}
结果
main : abc
Thread-0 : null
同一个 ThreadLocal 变量在父线程中被设置值后 , 在子线程中 是获取不到的。
根据上节的介绍,这应该是正常现象,因为在子线程 thread 里面调用 get 方法时当前线程
为 thread 线程,而这里调用 set 方法设置线程变量的是 main 线程,两者是不同的线程,自
然子线程访 问时返回 null
InheritableThreadLocal
可以有办法让子线程能访问到父线程中的值
InheritableThradLocal 应运 而 生。 InheritableThreadLocal
继承自 ThreadLocal , 其提供了一个特性,就是让子线程可 以访问在父线程中设置的本地
变量
package com.ghgcn.threadstudy.lesson01;
/**
* @author 刘楠
* @since 2019/7/1
*/
public class TestThreadLocal02 {
private static ThreadLocal<String> threadLocal = new InheritableThreadLocal<>();
public static void main(String[] args) {
threadLocal.set("abc");
Thread thread = new Thread(()->{
System.out.println(Thread.currentThread().getName()+" : "+threadLocal.get());
});
thread.start();
System.out.println("main : "+threadLocal.get());
}
}
结果
main : abc
Thread-0 : abc
InheritableThreadLocal
public class InheritableThreadLocal<T> extends ThreadLocal<T> {
//1
protected T childValue(T parentValue) {
return parentValue;
}
//2.获取的是 inheritableThreadLocals 而不再是 threadLocals
ThreadLocalMap getMap(Thread t) {
return t.inheritableThreadLocals;
}
//3. 重写了 createMap 方法
void createMap(Thread t, T firstValue) {
//那么现在当第/一次调用 set 方法时,创建的是当前线程的 inheritableThreadLocals 变量的实例而不再是threadLocals 而是inheritableThreadLocals
// ThreadLocal.ThreadLocalMap threadLocals = null;
//ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
}
}
在 InheritableThreadLocal 的类 , 变量 inheritableThreadLocals 替 代 了threadLocals