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 map size-->0 //子线程中threadLocal变量重新初始化
inheritableThreadLocal map size-->2 //父子线程中inheritableThreadLocal变量指向同一个对象
threadLocal map put content-->{java.lang.ThreadLocal@c236992=test}
//子线程中inheritableThreadLocal的Map中包含一个threadLocal变量,该变量重新初始化
sub thread inheritableThreadLocal map value-->pool-1-thread-1,origal value-->str2
sub thread set new value-->478237
sub thread inheritableThreadLocal map value-->str1,origal value-->str1
sub thread set new value-->482155
================test one after================
//父线程中threadLocal变量和inheritableThreadLocal变量依然指向同一个对象
true
//用于父子线程的inheritableThreadLocal变量指向同一个对象,子线程中修改了value值,父线程也看得到
main thread threadLocal value-->str2,origal value-->478237
main thread threadLocal value-->str1,origal value-->482155
================test two================
//线程复用情形线下,job看到的是上一次job运行结束的存储的线程变量,没有重新初始化
threadLocal map size-->1,content-->{java.lang.ThreadLocal@c236992=test}
inheritableThreadLocal map size-->2
sub thread inheritableThreadLocal map value-->478237,origal value-->478237
sub thread set new value-->415633
sub thread inheritableThreadLocal map value-->482155,origal value-->482155
sub thread set new value-->348084
================test two after================
true
main thread threadLocal value-->new str2,origal value-->415633
main thread threadLocal value-->new str,origal value-->348084
Process finished with exit code 0
二、线程池线程复用的原理
参考:https://blog.csdn.net/hotdust/article/details/64905254
总结:Thread对象实例化后只能接受一个Runable实例,运行完成后自动销毁。确保Thread对象执行完一个Runable任务不退出的秘密在于,将多个待执行的Runable放入一个队列中,子线程运行时从队列中中取待执行的Ruanable,如果取不到则阻塞休眠,确保该线程不会退出。
三、transmittable-thread-local使用
transmittable-thread-local对执行子线程任务的接口类java.lang.Runnable, java.lang.Callable以及java 8 引进的java.util.concurrent.RecursiveAction,java.util.concurrent.RecursiveTask 提供了对应的包装类,对常用的线程池接口类java.util.concurrent.Executor,java.util.concurrent.ExecutorService提供了对应的包装类。可以利用这两类包装类编写代码,也可以利用对业务代码无感知零侵入的java agent方式。
参考如下测试用例:
@Test
public void test2() throws Exception{
TransmittableThreadLocal<String> str=new TransmittableThreadLocal<>();
str.set("str");
Runnable job= TtlRunnable.get(new Runnable() {
@Override
public void run() {
System.out.println("str origal value-->"+str.get());
str.set(RandomStringUtils.randomNumeric(6));
System.out.println("str new value-->"+str.get());
}
});
ExecutorService executorService=Executors.newFixedThreadPool(1);
for(int i=0;i<3;i++){
executorService.submit(job);
}
executorService.shutdown();
executorService.awaitTermination(5, TimeUnit.SECONDS);
}
@Test
public void test3() throws Exception{
TransmittableThreadLocal<String> str=new TransmittableThreadLocal<>();
str.set("str");
Runnable job= new Runnable() {
@Override
public void run() {
System.out.println("str origal value-->"+str.get());
str.set(RandomStringUtils.randomNumeric(6));
System.out.println("str new value-->"+str.get());
}
};
ExecutorService executorService= TtlExecutors.getTtlExecutorService(Executors.newFixedThreadPool(1));
for(int i=0;i<3;i++){
executorService.submit(job);
}
executorService.shutdown();
executorService.awaitTermination(5, TimeUnit.SECONDS);
}
@Test
public void test4() throws Exception{
TransmittableThreadLocal<String> str=new TransmittableThreadLocal<>();
str.set("str");
Runnable job= new Runnable() {
@Override
public void run() {
System.out.println("str origal value-->"+str.get());
str.set(RandomStringUtils.randomNumeric(6));
System.out.println("str new value-->"+str.get());
}
};
ExecutorService executorService= Executors.newFixedThreadPool(1);
for(int i=0;i<3;i++){
executorService.submit(job);
}
executorService.shutdown();
executorService.awaitTermination(5, TimeUnit.SECONDS);
}
注意test4在启动前需要加上启动参数-javaagent:D:\git\transmittable-thread-local\target\original-transmittable-thread-local-2.7.0-SNAPSHOT.jar,-javaagent后为本地的jar包路径,ideal中设置如下:
四、transmittable-thread-local实现原理
transmittable-thread-local的核心实现在TransmittableThreadLocal类,该类继承自InheritableThreadLocal类,以TtlRunnable的实现为例说明。
TtlRunnable的核心代码说明如下:
//各种静态包装方法最终都会走到此构造方法
private TtlRunnable(Runnable runnable, boolean releaseTtlValueReferenceAfterRun) {
/*
1、capture()方法返回的对象类型是Map<TransmittableThreadLocal<?>, Object>,该方法在父线程中执行,
返回值是此时父线程包含的TransmittableThreadLocal变量及其在父线程中的取值。
2、当子线程执行TtlRunnable的run方法时,capturedRef也会随着TtlRunnable实例传入子线程中,子线程capturedRef变量中包含的
TransmittableThreadLocal变量继承自父线程,线程复用的情形下则跟上一次该子线程执行任务完成后的变量状态一致。
*/
this.capturedRef = new AtomicReference<Object>(capture());
this.runnable = runnable;
this.releaseTtlValueReferenceAfterRun = releaseTtlValueReferenceAfterRun;
}
/**
* wrap method {@link Runnable#run()}.
*/
@Override
public void run() {
/*
1、run方法在子线程中执行
2、replay方法将capturedRef中保存的来自父线程中TransmittableThreadLocal变量写入到子线程对应的变量中,保证子线程每次执行时
TransmittableThreadLocal变量的初始值一致。该方法返回子线程此时包含的TransmittableThreadLocal变量。
3、restore方法用于还原子线程中包含的TransmittableThreadLocal变量至run方法开始执行的状态
*/
Object captured = capturedRef.get();
if (captured == null || releaseTtlValueReferenceAfterRun && !capturedRef.compareAndSet(captured, null)) {
throw new IllegalStateException("TTL value reference is released after run!");
}
Object backup = replay(captured);
try {
runnable.run();
} finally {
restore(backup);
}
}
TransmittableThreadLocal类的核心代码在子线程中执行,通多debug断点调试时容易中断,因此关键操作增加日志输出,便于理解代码运行过程,代码说明如下:
public class TransmittableThreadLocal<T> extends InheritableThreadLocal<T> {
private static final Logger logger = Logger.getLogger(TransmittableThreadLocal.class.getName());
protected T copy(T parentValue) {
return parentValue;
}
/**
* Callback method before task object({@link TtlRunnable}/{@link TtlCallable}) execute.
*/
protected void beforeExecute() {
}
/**
* Callback method after task object({@link TtlRunnable}/{@link TtlCallable}) execute.
*/
protected void afterExecute() {
}
//重写get和set方法确保变量备份在hold变量中
@Override
public final T get() {
T value = super.get();
if (null != value) {
addValue();
}
return value;
}
@Override
public final void set(T value) {
super.set(value);
if (null == value) {
removeValue();
} else {
addValue();
}
}
@Override
public final void remove() {
removeValue();
super.remove();
}
private void superRemove() {
super.remove();
}
private T superGet(){
return super.get();
}
private T copyValue() {
return copy(get());
}
/*
1、此hold变量是TransmittableThreadLocal的静态 InheritableThreadLocal 变量,只初始化一次,所有TransmittableThreadLocal实例共享,
借助重写的get和set方法,同一线程内所有的TransmittableThreadLocal变量都会保存到该线程内的holder变量中
2、holder变量重写了InheritableThreadLocal的childValue(T parent)方法,默认实现是将parent直接返回,使父子线程的InheritableThreadLocal
变量指向同一个对象,子线程对该对象的修改在父线程中也是可见的。重写后父子线程中InheritableThreadLocal是两个独立的对象,只是子线程的
TransmittableThreadLocal变量初始化的时候取值和父线程一致。
*/
private static InheritableThreadLocal<Map<TransmittableThreadLocal<?>, ?>> holder =
new InheritableThreadLocal<Map<TransmittableThreadLocal<?>, ?>>() {
@Override
protected Map<TransmittableThreadLocal<?>, ?> initialValue() {
return new WeakHashMap<TransmittableThreadLocal<?>, Object>();
}
@Override
protected Map<TransmittableThreadLocal<?>, ?> childValue(Map<TransmittableThreadLocal<?>, ?> parentValue) {
return new WeakHashMap<TransmittableThreadLocal<?>, Object>(parentValue);
}
};
private void addValue() {
if (!holder.get().containsKey(this)) {
holder.get().put(this, null); // WeakHashMap supports null value.
System.out.println("addValue holder size-->"+holder.get().size()+",add value-->"+this.get());
}
}
private void removeValue() {
holder.get().remove(this);
System.out.println("removeValue holder size-->"+holder.get().size());
}
private static void doExecuteCallback(boolean isBefore) {
for (Map.Entry<TransmittableThreadLocal<?>, ?> entry : holder.get().entrySet()) {
TransmittableThreadLocal<?> threadLocal = entry.getKey();
try {
if (isBefore) {
threadLocal.beforeExecute();
} else {
threadLocal.afterExecute();
}
} catch (Throwable t) {
if (logger.isLoggable(Level.WARNING)) {
logger.log(Level.WARNING, "TTL exception when " + (isBefore ? "beforeExecute" : "afterExecute") + ", cause: " + t.toString(), t);
}
}
}
}
/**
* Debug only method!
*/
static void dump(String title) {
if (title != null && title.length() > 0) {
System.out.printf("Start TransmittableThreadLocal[%s] Dump...\n", title);
} else {
System.out.println("Start TransmittableThreadLocal Dump...");
}
for (Map.Entry<TransmittableThreadLocal<?>, ?> entry : holder.get().entrySet()) {
final TransmittableThreadLocal<?> key = entry.getKey();
System.out.println(key.get());
}
System.out.println("TransmittableThreadLocal Dump end!");
}
/**
* Debug only method!
*/
static void dump() {
dump(null);
}
/**
*/
public static class Transmitter {
/**
* 捕获父线程的所有TransmittableThreadLocal变量及其变量值,将父线程此时的TransmittableThreadLocal变量备份
*/
public static Object capture() {
System.out.println("capture hold size-->"+holder.get().size());
Map<TransmittableThreadLocal<?>, Object> captured = new HashMap<TransmittableThreadLocal<?>, Object>();
for (TransmittableThreadLocal<?> threadLocal : holder.get().keySet()) {
captured.put(threadLocal, threadLocal.copyValue());
}
return captured;
}
/**
* Replay the captured {@link TransmittableThreadLocal} values from {@link #capture()},
* and return the backup {@link TransmittableThreadLocal} values in current thread before replay.
*
* 1、capturedMap中保存的TransmittableThreadLocal变量的取值在父子线程中不一定相同,但是TransmittableThreadLocal变量在Map中对应的value不变,
* 即始终是capture()执行时父线程的TransmittableThreadLocal变量的取值。
* 2、
*
*/
public static Object replay(Object captured) {
@SuppressWarnings("unchecked")
Map<TransmittableThreadLocal<?>, Object> capturedMap = (Map<TransmittableThreadLocal<?>, Object>) captured;
Map<TransmittableThreadLocal<?>, Object> backup = new HashMap<TransmittableThreadLocal<?>, Object>();
System.out.println("replay before holder size-->"+holder.get().size());
try {
for (Iterator<? extends Map.Entry<TransmittableThreadLocal<?>, ?>> iterator = holder.get().entrySet().iterator();
iterator.hasNext(); ) {
Map.Entry<TransmittableThreadLocal<?>, ?> next = iterator.next();
TransmittableThreadLocal<?> threadLocal = next.getKey();
// backup
backup.put(threadLocal, threadLocal.get());
//此处操作和setTtlValuesTo方法可以确保holder中保存的TransmittableThreadLocal变量和capturedMap一致
//即恢复子线程中的holder变量至capture()执行时主线程的holder变量的状态
if (!capturedMap.containsKey(threadLocal)) {
iterator.remove();
System.out.println("replay remove value-->"+threadLocal.superGet()+",holder size-->"+holder.get().size());
threadLocal.superRemove();
}
}
// set values to captured TTL
setTtlValuesTo(capturedMap);
// call beforeExecute callback
doExecuteCallback(true);
System.out.println("replay after holder size-->"+holder.get().size());
} catch (Exception e) {
System.out.println(e.getMessage());
}
return backup;
}
/**
* Restore the backup {@link TransmittableThreadLocal} values from {@link Transmitter#replay(Object)}.
*
* @param backup the backup {@link TransmittableThreadLocal} values from {@link Transmitter#replay(Object)}
* @since 2.3.0
*/
public static void restore(Object backup) {
@SuppressWarnings("unchecked")
Map<TransmittableThreadLocal<?>, Object> backupMap = (Map<TransmittableThreadLocal<?>, Object>) backup;
// call afterExecute callback
doExecuteCallback(false);
System.out.println("restore before holder size-->"+holder.get().size());
for (Iterator<? extends Map.Entry<TransmittableThreadLocal<?>, ?>> iterator = holder.get().entrySet().iterator();
iterator.hasNext(); ) {
Map.Entry<TransmittableThreadLocal<?>, ?> next = iterator.next();
TransmittableThreadLocal<?> threadLocal = next.getKey();
// 同replay,确保backUp中包含的TransmittableThreadLocal变量和holder中保持一致,即恢复线程的holder变量至此次job
//开始运行的状态
if (!backupMap.containsKey(threadLocal)) {
iterator.remove();
System.out.println("restore remove value-->"+threadLocal.superGet()+",holder size-->"+holder.get().size());
threadLocal.superRemove();
}
}
// restore TTL values
setTtlValuesTo(backupMap);
System.out.println("restore after holder size-->"+holder.get().size());
}
private static void setTtlValuesTo(Map<TransmittableThreadLocal<?>, Object> ttlValues) {
for (Map.Entry<TransmittableThreadLocal<?>, Object> entry : ttlValues.entrySet()) {
@SuppressWarnings("unchecked")
TransmittableThreadLocal<Object> threadLocal = (TransmittableThreadLocal<Object>) entry.getKey();
/*
1、当传入的值是capturedMap时,entry.getValue()为父线程中此变量的取值,如果是backupMap则是子线程中次变量的取值
2、如果此时子线程的holder变量中不包含此变量,则通过set方法加入到holder中
*/
System.out.println("setTtlValuesTo before value-->"+threadLocal.get());
threadLocal.set(entry.getValue());
System.out.println("setTtlValuesTo after value-->"+threadLocal.get());
}
}
/**
* Util method for simplifying {@link #replay(Object)} and {@link #restore(Object)} operation.
*
*/
public static <R> R runSupplierWithCaptured(Object captured, Supplier<R> bizLogic) {
Object backup = replay(captured);
try {
return bizLogic.get();
} finally {
restore(backup);
}
}
/**
* Util method for simplifying {@link #replay(Object)} and {@link #restore(Object)} operation.
*/
public static <R> R runCallableWithCaptured(Object captured, Callable<R> bizLogic) throws Exception {
Object backup = replay(captured);
try {
return bizLogic.call();
} finally {
restore(backup);
}
}
private Transmitter() {
throw new InstantiationError("Must not instantiate this class");
}
}
}
参考测试用例如下:
@Test
public void test8() throws Exception {
Logger logger= LoggerFactory.getLogger(getClass());
ExecutorService executors= Executors.newFixedThreadPool(1);
TransmittableThreadLocal<String> str=new TransmittableThreadLocal<>();
TransmittableThreadLocal<String> str2=new TransmittableThreadLocal<>();
str.set("str1");
str2.set("str2");
System.out.println("==================init===============");
System.out.println("str-->"+str.get());
System.out.println("str2-->"+str2.get());
Runnable runnable=new Runnable() {
@Override
public void run() {
System.out.println("==============before set==============");
System.out.println("str-->"+str.get());
System.out.println("str2-->"+str2.get());
str.set(RandomStringUtils.randomNumeric(5));
str2.set(RandomStringUtils.randomNumeric(5));
System.out.println("==============after set==============");
System.out.println("str-->"+str.get());
System.out.println("str2-->"+str2.get());
TransmittableThreadLocal<String> test=new TransmittableThreadLocal<>();
test.set(RandomStringUtils.randomNumeric(5));
System.out.println("add new-->"+test.get());
}
};
Runnable job=TtlRunnable.get(runnable);
TransmittableThreadLocal<String> str3=new TransmittableThreadLocal<>();
TransmittableThreadLocal<String> str4=new TransmittableThreadLocal<>();
str3.set("str3");
str4.set("str4");
System.out.println("===============test one===============");
executors.submit(job);
executors.awaitTermination(5,TimeUnit.SECONDS);
TransmittableThreadLocal<String> str5=new TransmittableThreadLocal<String>(){
@Override
protected String initialValue() {
return "str5";
}
};
TransmittableThreadLocal<String> str6=new TransmittableThreadLocal<String>(){
@Override
protected String initialValue() {
return "str6";
}
};
str5.get();
str6.get();
str.set("new str");
str2.set("new str2");
System.out.println("===============test two===============");
executors.submit(job);
executors.awaitTermination(5,TimeUnit.SECONDS);
System.out.println("===============test three===============");
job=TtlRunnable.get(runnable);
executors.submit(job);
executors.awaitTermination(5,TimeUnit.SECONDS);
}
测试用例运行结果说明如下:
//主线程str1和str2变量初始化
addValue holder size-->1,add value-->str1
addValue holder size-->2,add value-->str2
==================init===============
str-->str1
str2-->str2
//实例化TtlRunnable,此时主线程的holder变量size为2
capture hold size-->2
//主线程str3和str4变量初始化,此时主线程的holder变量size为4
addValue holder size-->3,add value-->str3
addValue holder size-->4,add value-->str4
===============test one===============
//线程创建完成,此时子线程的holder size和父线程相同,都为4
replay before holder size-->4
//capture()方法执行时没有str3和str4变量,因此从子线程的holder变量中移除str3和str4
replay remove value-->str4,holder size-->3
replay remove value-->str3,holder size-->2
//子线程的str1和str2变量初始化值和父线程一致
setTtlValuesTo before value-->str1
setTtlValuesTo after value-->str1
setTtlValuesTo before value-->str2
setTtlValuesTo after value-->str2
//子线程的holder变量和captureMap保持一致
replay after holder size-->2
==============before set==============
str-->str1
str2-->str2
==============after set==============
str-->75400
str2-->71067
//执行run方法时往子线程holder变量中新增了一个变量,holder size变为3
addValue holder size-->3,add value-->62653
add new-->62653
restore before holder size-->3
//因为backupMap中不包含新增的变量,restore时从holder中移除
restore remove value-->62653,holder size-->2
//holder中原来包含的str3和str4变量在replay方法时被移除,所以before value为null
setTtlValuesTo before value-->null
addValue holder size-->3,add value-->str3
setTtlValuesTo after value-->str3
setTtlValuesTo before value-->75400
setTtlValuesTo after value-->str1
setTtlValuesTo before value-->71067
setTtlValuesTo after value-->str2
setTtlValuesTo before value-->null
addValue holder size-->4,add value-->str4
setTtlValuesTo after value-->str4
//恢复子线程的holder变量为线程创建时的状态
restore after holder size-->4
//主线程新增变量str5和str6,并且此时str1和str2都设置了新的取值,此时主线程的holder size为6
addValue holder size-->5,add value-->shl5
addValue holder size-->6,add value-->shl6
===============test two===============
//holder变量改写了child(T parent)方法,父子线程的holder变量是两个独立的对象,子线程的holder变量 size依然是4
replay before holder size-->4
replay remove value-->str4,holder size-->3
replay remove value-->str3,holder size-->2
//captureMap是保存capture()方法执行时父线程的变量值,因为父线程的str1和str2更新时不能同步更新captureMap中的值,
//所以captureMap保存的值依然是更新前的值
setTtlValuesTo before value-->str1
setTtlValuesTo after value-->str1
setTtlValuesTo before value-->str2
setTtlValuesTo after value-->str2
replay after holder size-->2
==============before set==============
str-->str1
str2-->str2
==============after set==============
str-->24610
str2-->90489
addValue holder size-->3,add value-->49216
add new-->49216
restore before holder size-->3
restore remove value-->49216,holder size-->2
setTtlValuesTo before value-->null
addValue holder size-->3,add value-->str3
setTtlValuesTo after value-->str3
setTtlValuesTo before value-->24610
setTtlValuesTo after value-->str1
setTtlValuesTo before value-->90489
setTtlValuesTo after value-->str2
setTtlValuesTo before value-->null
addValue holder size-->4,add value-->str4
setTtlValuesTo after value-->str4
restore after holder size-->4
===============test three===============
//实例化一个新的TtlRunnable变量
capture hold size-->6
//str5和str6是后面新增的,holder变量中没有
//holder变量保存的是str和str2变量是线程初始化时从父线程继承的值,通过captureMap更新至与父线程一致
replay before holder size-->4
setTtlValuesTo before value-->str3
setTtlValuesTo after value-->str3
setTtlValuesTo before value-->str1
setTtlValuesTo after value-->new str
addValue holder size-->5,add value-->shl5
setTtlValuesTo before value-->shl5
setTtlValuesTo after value-->shl5
setTtlValuesTo before value-->str2
setTtlValuesTo after value-->new str2
addValue holder size-->6,add value-->shl6
setTtlValuesTo before value-->shl6
setTtlValuesTo after value-->shl6
setTtlValuesTo before value-->str4
setTtlValuesTo after value-->str4
replay after holder size-->6
==============before set==============
str-->new str
str2-->new str2
==============after set==============
str-->28860
str2-->24749
addValue holder size-->7,add value-->72427
add new-->72427
restore before holder size-->7
restore remove value-->shl5,holder size-->6
restore remove value-->shl6,holder size-->5
restore remove value-->72427,holder size-->4
setTtlValuesTo before value-->str3
setTtlValuesTo after value-->str3
setTtlValuesTo before value-->28860
//str1和str2又恢复至初始状态
setTtlValuesTo after value-->str1
setTtlValuesTo before value-->24749
setTtlValuesTo after value-->str2
setTtlValuesTo before value-->str4
setTtlValuesTo after value-->str4
//恢复子线程的holder变量至线程创建时子线程的holder变量状态
restore after holder size-->4
四、TransmittableThreadLocal 使用的注意事项
如果TtlRunnable只实例化一次然后被重复提交运行则子线程执行任务时获取的TransmittableThreadLocal变量不是最新的,每次执行时都重新实例化可以确保子线程执行任务时获取的TransmittableThreadLocal变量是最新的。