transmittable-thread-local主要是用于线程池等线程复用时,需要确保子线程的InheritableThreadLocal变量永远跟该线程创建时的父线程的InheritableThreadLocal一致的场景下,弥补InheritableThreadLocal的不足,通常应用于方法级监控的中间件中。
一、ThreadLocal和InheritableThreadLocal的差异
ThreadLocal 实现原理参考 https://www.cnblogs.com/dolphin0520/p/3920407.html
InheritableThreadLocal 实现原理参考 https://blog.csdn.net/ni357103403/article/details/51970748
总结:1、父子线程的ThreadLocal变量是互相独立的,没有任何关联的,而子线程的InheritableThreadLocal变量在初始化完成时,跟父线程的InheritableThreadLocal变量保存的对象是同一个。如果父子线程只是修改该对象属性,而没有修改对象引用,则此时InheritableThreadLocal变量等价于普通的变量。
2、ThreadLocal 和 InheritableThreadLocal变量都是在线程创建的时候才会初始化,线程复用的情况下,程序访问到的ThreadLocal 和 InheritableThreadLocal变量是上一次job运行完成后的可能被修改的变量。
参考如下测试用例:
package threadLocal.test;
import org.apache.commons.lang3.RandomStringUtils;
import org.junit.Test;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class MyTest3 {
@Test
public void name() throws Exception{
ThreadLocal<Map<ThreadLocal<String>,String>> threadLocal=new ThreadLocal<Map<ThreadLocal<String>,String>>(){
@Override
protected Map<ThreadLocal<String>,String> initialValue() {
return new HashMap<>();
}
};
InheritableThreadLocal<Map<ThreadLocal<String>,String>> inheritableThreadLocal=new InheritableThreadLocal<Map<ThreadLocal<String>,String>>(){
@Override
protected Map<ThreadLocal<String>,String> initialValue() {
return new HashMap<>();
}
};
Map<ThreadLocal<String>,String> threadLocalStringMap=new HashMap<>();
InheritableThreadLocal<String> str1=new InheritableThreadLocal<>();
str1.set("str1");
threadLocalStringMap.put(str1, "str1");
ThreadLocal<String> str2=new ThreadLocal<String>(){
@Override
protected String initialValue() {
return Thread.currentThread().getName();
}
};
str2.set("str2");
threadLocalStringMap.put(str2, "str2");
threadLocal.set(threadLocalStringMap);
inheritableThreadLocal.set(threadLocalStringMap);
ExecutorService executorService= Executors.newFixedThreadPool(1);
Runnable runnable=new Runnable() {
@Override
public void run() {
System.out.println("threadLocal map size-->"+threadLocal.get().size());
System.out.println("inheritableThreadLocal map size-->"+inheritableThreadLocal.get().size());
ThreadLocal<String> test=new ThreadLocal<>();
test.set("test");
threadLocal.get().put(test, "test");
System.out.println("threadLocal map put content-->"+threadLocal.get());
for(Map.Entry<ThreadLocal<String>,String> entry :inheritableThreadLocal.get().entrySet()){
System.out.println(" sub thread inheritableThreadLocal map value-->"+entry.getKey().get()+",origal value-->"+entry.getValue());
String randomStr=RandomStringUtils.randomNumeric(6);
entry.getKey().set(randomStr);
entry.setValue(randomStr);
System.out.println("sub thread set new value-->"+randomStr);
}
}
};
System.out.println("================test one================");
executorService.submit(runnable);
executorService.awaitTermination(2, TimeUnit.SECONDS);
System.out.println("================test one after================");
System.out.println(threadLocal.get().equals(inheritableThreadLocal.get()));
for(Map.Entry<ThreadLocal<String>,String> entry :inheritableThreadLocal.get().entrySet()){
System.out.println("main thread threadLocal value-->"+entry.getKey().get()+",origal value-->"+entry.getValue());
}
str1.set("new str");
str2.set("new str2");
System.out.println("================test two================");
runnable=new Runnable() {
@Override
public void run() {
System.out.println("threadLocal map size-->"+threadLocal.get().size()+",content-->"+threadLocal.get());
System.out.println("inheritableThreadLocal map size-->"+inheritableThreadLocal.get().size());
for(Map.Entry<ThreadLocal<String>,String> entry :inheritableThreadLocal.get().entrySet()){
System.out.println("sub thread inheritableThreadLocal map value-->"+entry.getKey().get()+",origal value-->"+entry.getValue());
String randomStr=RandomStringUtils.randomNumeric(6);
entry.getKey().set(randomStr);
entry.setValue(randomStr);
System.out.println("sub thread set new value-->"+randomStr);
}
}
};
executorService.submit(runnable);
executorService.awaitTermination(2, TimeUnit.SECONDS);
System.out.println("================test two after================");
System.out.println(threadLocal.get().equals(inheritableThreadLocal.get()));
for(Map.Entry<ThreadLocal<String>,String> entry :inheritableThreadLocal.get().entrySet()){
System.out.println("main thread threadLocal value-->"+entry.getKey().get()+",origal value-->"+entry.getValue());
}
}
}
该测试用例运行的结果及说明如下:
================test one================
threadLocal