ThreadLocal -->InheritableThreadLocal-->TransmittableThreadLocal解决线程池中变量传值问题
InheritableThreadLocal ITL可以解决父线程传本地变量给子线程,但是无法解决线程池模式下正确传值。
TransmittableThreadLocal TTL,在线程池模式下,也可以正确的将父线程的本地变量传给子线程
TTL的用法:
加入依赖:
<dependency> <groupId>com.alibaba</groupId> <artifactId>transmittable-thread-local</artifactId> <version>2.13.0-Beta1</version> </dependency>
1.线程池使用TtlExecutors.getTtlExecutorService封装:
TtlExecutors.getTtlExecutorService(executorService);
2.变量使用TransmittableThreadLocal
TransmittableThreadLocal<String> transmittableThreadLocal=new TransmittableThreadLocal<>();
上代码可以看到区别:
1.工厂类:MyFactory.java public class MyFactory implements ThreadFactory { private String name; private AtomicLong count = new AtomicLong(0); public MyFactory(String name){ this.name=name; } @Override public Thread newThread(Runnable r) { String a = count.getAndIncrement() + ""; System.out.println("创建线程,名字:" + name+"_"+a); Thread thread = new Thread(r); thread.setName(name+"_"+a); thread.setDaemon(true); return thread; } }
2.线程:ThreadOne.java
public class ThreadOne implements Runnable{
private CountDownLatch latch;
private String name;
ThreadOne(CountDownLatch l,String name){
this.latch=l;
this.name=name;
};
@Override
public void run() {
System.out.println("线程名字:"+name+" tl:"+TwoMain.threadLocalValue.get()+" ITL "+TwoMain.inheritableThreadLocalValue.get()
+" TTL:"+TwoMain.transmittableThreadLocal.get());
try {
Thread.sleep(1000*1);
} catch (InterruptedException e) {
e.printStackTrace();
}
latch.countDown();
}
}
3.main函数
public class TwoMain {
public static ThreadLocal<String> threadLocalValue = new ThreadLocal<>();
public static InheritableThreadLocal<String> inheritableThreadLocalValue = new InheritableThreadLocal<>();
public static TransmittableThreadLocal<String> transmittableThreadLocal=new TransmittableThreadLocal<>();
public static void main(String[] args) {
ExecutorService executorService = new ThreadPoolExecutor(5, 10, 0, TimeUnit.SECONDS, new ArrayBlockingQueue(6), new MyFactory("线程池"));
ExecutorService ttlExecutorService = TtlExecutors.getTtlExecutorService(executorService);
CountDownLatch latch = new CountDownLatch(30);
threadLocalValue.set("AAAAAA");
inheritableThreadLocalValue.set("AAAAAA");
transmittableThreadLocal.set("AAAAAA");
for (int i = 0; i < 30; i++) {
ThreadOne t = new ThreadOne(latch, i + "");
try {
ttlExecutorService.submit(t);
} catch (Exception e) {
// System.out.println(e.getMessage());
latch.countDown();
}
}
try {
System.out.println("线程名字:"+Thread.currentThread().getName()+" threadlocal:"+threadLocalValue.get()+" inheritthreadLocal:"+inheritableThreadLocalValue.get());
System.out.println("我先睡会儿!!");
latch.await();
System.out.println("我开始下一场");
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我把TL/ITL/TTL值都设置成BBBBB");
threadLocalValue.set("BBBBB");
inheritableThreadLocalValue.set("BBBBB");
transmittableThreadLocal.set("BBBBB");
for (int i = 0; i < 30; i++) {
ThreadOne t = new ThreadOne(latch, i + "B");
try {
ttlExecutorService.submit(t);
} catch (Exception e) {
// System.out.println(e.getMessage());
latch.countDown();
}
}
}
}
结果:
创建线程,名字:线程池_0
创建线程,名字:线程池_1
创建线程,名字:线程池_2
创建线程,名字:线程池_3
线程名字:1 tl:null ITL AAAAAA TTL:AAAAAA
线程名字:0 tl:null ITL AAAAAA TTL:AAAAAA
创建线程,名字:线程池_4
线程名字:2 tl:null ITL AAAAAA TTL:AAAAAA
线程名字:3 tl:null ITL AAAAAA TTL:AAAAAA
线程名字:4 tl:null ITL AAAAAA TTL:AAAAAA
创建线程,名字:线程池_5
创建线程,名字:线程池_6
创建线程,名字:线程池_7
创建线程,名字:线程池_8
线程名字:11 tl:null ITL AAAAAA TTL:AAAAAA
创建线程,名字:线程池_9
线程名字:12 tl:null ITL AAAAAA TTL:AAAAAA
线程名字:14 tl:null ITL AAAAAA TTL:AAAAAA
线程名字:15 tl:null ITL AAAAAA TTL:AAAAAA
线程名字:13 tl:null ITL AAAAAA TTL:AAAAAA
线程名字:main threadlocal:AAAAAA inheritthreadLocal:AAAAAA
我先睡会儿!!
线程名字:6 tl:null ITL AAAAAA TTL:AAAAAA
线程名字:5 tl:null ITL AAAAAA TTL:AAAAAA
线程名字:7 tl:null ITL AAAAAA TTL:AAAAAA
线程名字:9 tl:null ITL AAAAAA TTL:AAAAAA
线程名字:8 tl:null ITL AAAAAA TTL:AAAAAA
线程名字:10 tl:null ITL AAAAAA TTL:AAAAAA
我开始下一场
我把TL/ITL/TTL值都设置成BBBBB
线程名字:0B tl:null ITL AAAAAA TTL:BBBBB
线程名字:1B tl:null ITL AAAAAA TTL:BBBBB
线程名字:3B tl:null ITL AAAAAA TTL:BBBBB
线程名字:2B tl:null ITL AAAAAA TTL:BBBBB
线程名字:4B tl:null ITL AAAAAA TTL:BBBBB
创建线程,名字:线程池_10
创建线程,名字:线程池_11
线程名字:11B tl:null ITL BBBBB TTL:BBBBB
创建线程,名字:线程池_12
线程名字:12B tl:null ITL BBBBB TTL:BBBBB
创建线程,名字:线程池_13
创建线程,名字:线程池_14
线程名字:14B tl:null ITL BBBBB TTL:BBBBB
线程名字:13B tl:null ITL BBBBB TTL:BBBBB
线程名字:15B tl:null ITL BBBBB TTL:BBBBB
Process finished with exit code 0
可以看到:
threadlocal不会把值传给子线程
当更改父线程的变量之后,线程池不新建线程时,ITL中值,依然是旧值。TTL始终是正确的。