1、ThreadLocal使用及问题
代码
public static void threadLocal(){
ThreadLocal threadLocal = new ThreadLocal();
threadLocal.set(4);
System.out.println("parent - " +threadLocal.get());
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("child -" +threadLocal.get());
}
}).start();
}
运行结果
parent - 4
child -null
可以看出当在主线程中开启一个行程时是获取不到在主线程中set的值的,InheritableThreadLocal解决了这个问题
InheritableThreadLocal使用及问题
代码
public static void inherThreadLocal(){
ThreadLocal threadLocal = new InheritableThreadLocal();
threadLocal.set(4);
System.out.println("parent - " +threadLocal.get());
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("child -" + threadLocal.get());
}
}).start();
}
运行结果
parent - 4
child -4
为什么可以获取呢。我们看一下Thread的代码中
获取父线程,其中inheritableThreadLocals属性是非null的,接着往下的看
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
核心在这,会将父线程的inheritableThreadLocals传递给当前子线程。createInheritedMap方法会重新n创建一个map,这就会有一个问题如果是使用线程池时。可能不在重新创建新的线程。那这时候是不是就传递不了了。
代码如下
public static void withThreadPool(){
ThreadLocal threadLocal = new InheritableThreadLocal();
ExecutorService executorService = Executors.newFixedThreadPool(1);
threadLocal.set(1);
//这时线程池会进行初始化线程
executorService.execute(new Runnable() {
@Override
public void run() {
System.out.println("child1 - " +threadLocal.get());
}
});
executorService.execute(new Runnable() {
@Override
public void run() {
System.out.println("child2 - " + threadLocal.get());
}
});
executorService.shutdown();
}
结果
child1 - 1
child2 - 1
好像没什么问题。猜想错了吗?我们换个写法代码如下
public static void withThreadPool(){
ThreadLocal threadLocal = new InheritableThreadLocal();
ExecutorService executorService = Executors.newFixedThreadPool(1);
//这时线程池会进行初始化线程
executorService.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("child1 - " +threadLocal.get());
}
});
threadLocal.set(1);
executorService.execute(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("child2 - " + threadLocal.get());
}
});
executorService.shutdown();
}
结果
child1 - null
child2 - null
获取不到了,两块的代码有什么不同呢。仔细看下。threadLocal.set(1);放在了excute之后,那这是为什么呢。看源码execute方法
当工作线程数小于核心线程数时会调用addWorker方法,接下来我们看该方法,其中有
w = new Worker(firstTask);
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
可以看到是进行了new Thread 操作,上面我们知道在创建线程的时候会将父线程的map传递给子线程。
那我们将线程池的数量大小设置成2个时,
结果
child1 - null
child2 - 1
所以我们可以知道了问题所在 InheritableThreadLocal 在线程池的时候会有问题
解决方案: 阿里的transmittable-thread-local
TransmittableThreadLocal使用
代码
public class Test {
static ThreadLocal<String> parent = new TransmittableThreadLocal<>();
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(1);
ExecutorService ttlExecutorService = TtlExecutors.getTtlExecutorService(executorService);
Runnable task = new Task();
ttlExecutorService.submit(task);
TimeUnit.SECONDS.sleep(1);
parent.set("parent value");
ttlExecutorService.submit(task);
TimeUnit.SECONDS.sleep(1);
String value = parent.get();
System.out.println("out value: " + value);
ttlExecutorService.shutdown();
}
public static class Task implements Runnable {
@Override
public void run() {
System.out.println("=======");
String value1 = parent.get();
System.out.println("in value1: " + value1);
parent.set("child value");
String value2 = parent.get();
System.out.println("in value2 " + value2);
}
}
}
结果
=======
in value1: null
in value2 child value
=======
in value1: parent value
in value2 child value
out value: parent value
可以看到可以正常传递。
在这我只能仰望阿里的大佬