特点
ThreadLocal声明的变量是线程私有的成员变量,每个线程都有该变量的副本,线程对变量的修改对其他线程不可见。
InheritableThreadLocal声明的变量同样是线程私有的,但是子线程可以从父线程继承InheritableThreadLocal声明的变量。
子线程对InheritableThreadLocal变量的修改对父线程是不可见的,同样父线程对InheritableThreadLocal变量的修改对子线程也不可见。
子线程只是在初始化的时候继承父线程的InheritableThreadLocal变量值,初始化以后父线程对InheritableThreadLocal变量的修改对子线程不可见。
示例代码:
public class InheritableThreadLocalApp {
public static void main(String[] args) {
final InheritableThreadLocal<String> local1=new InheritableThreadLocal<String>();
final InheritableThreadLocal<HashMap> local2=new InheritableThreadLocal<HashMap>();
final HashMap<String,String> hashMap=new HashMap<>();
hashMap.put("1","1");
local1.set("1");
local2.set(hashMap);
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(2000);
System.out.println("2秒以后。。。。。");
// 仅仅能访问到 new Thread 之前的数据
System.out.println(Thread.currentThread().getName()+"-local1:"+local1.get());
local1.set("3");
HashMap<String,String> hashMap= local2.get();
hashMap.put("3","3");
System.out.println(Thread.currentThread().getName()+"-local2:"+local2.get().size());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
local1.set("2");
hashMap.put("2","2");
try {
Thread.sleep(5000);
System.out.println("5秒以后。。。。。");
System.out.println(Thread.currentThread().getName()+"-local1:"+local1.get());
System.out.println(Thread.currentThread().getName()+"-local2:"+local2.get().size());
} catch (InterruptedException e) {
e.printStackTrace();
}
ThreadUtil.waitExit();
}
}
运行结果
2秒以后。。。。。
Thread-0-local1:1
Thread-0-local2:3
2秒以后。。。。。
Thread-0-local1:3
Thread-0-local2:3
5秒以后。。。。。
main-local1:2
main-local2:3
2秒以后。。。。。
Thread-0-local1:3
Thread-0-local2:3
1) InheritableThreadLocal声明的变量同样是线程私有的,但是子线程可以从父线程继承InheritableThreadLocal声明的变量( local1.get() 获取值为1 说明这点)
2) 父线程无法拿到其子线程修改InheritableThreadLocal变量的值( local1 变量的值在子线程中设置为 3 后,父线程获取的值仍然是 2,这是因为父线程和子线程中local1 存储的已经不是同1个对象了)
3) 子线程对InheritableThreadLocal变量的修改对父线程是不可见的,同样父线程对InheritableThreadLocal变量的修改对子线程也不可见( local1变量的值在子线程中设置为 3 后,父线程获取的值仍然是 2)
4)子线程只是在初始化的时候继承父线程的InheritableThreadLocal变量值,初始化以后父线程对InheritableThreadLocal变量的修改对子线程不可见(见下面源码分析)
Thread 源码分析
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null, true);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
if (name == null) {
throw new NullPointerException("name cannot be null");
}
this.name = name;
Thread parent = currentThread();
/***************省略无关代码**************/
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
// 子线程初始化时继承父线程的对象
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
/***************省略无关代码**************/
}
static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
return new ThreadLocalMap(parentMap);
}
ThreadLocal 源码分析
private ThreadLocalMap(ThreadLocalMap parentMap) {
Entry[] parentTable = parentMap.table;
int len = parentTable.length;
setThreshold(len);
table = new Entry[len];
for (int j = 0; j < len; j++) {
Entry e = parentTable[j]; // 子线程继承的对象和父线程是同1个对象
if (e != null) {
@SuppressWarnings("unchecked")
ThreadLocal<Object> key = (ThreadLocal<Object>) e.get();
if (key != null) {
Object value = key.childValue(e.value);
Entry c = new Entry(key, value);
int h = key.threadLocalHashCode & (len - 1);
while (table[h] != null)
h = nextIndex(h, len);
table[h] = c;
size++;
}
}
}
}