大家都知道,子线程获取父线程的共享数据,可以通过InheritableThreadLocal。但这个是有个问题,我们来个测试用例看看结果
public class Demo {
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(4, 8, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100));
for (int i = 0; i < 10; i++) {
executor.execute(()->{
System.out.println("Test");
});
}
InheritableThreadLocal<String> stringInheritableThreadLocal = new InheritableThreadLocal<>();
stringInheritableThreadLocal.set("testest");
for (int i = 0; i < 10; i++) {
executor.execute(()->{
System.out.println(stringInheritableThreadLocal.get());
});
}
}
}
竟然null!传递失败了!为什么!?
因为InheritableThreadLocal的传递是父线程创建子线程的时候传递的,已创建好的线程是无法传递的。我们可以用什么解决 --- 阿里的 TransmittableThreadLocal
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
</dependency>
以下为测试demo
public class Demo {
public static void main(String[] args) throws InterruptedException {
ThreadPoolExecutor executor = new ThreadPoolExecutor(4, 8, 60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100));
Executor ttlExecutor = TtlExecutors.getTtlExecutor(executor);
for (int i = 0; i < 10; i++) {
ttlExecutor.execute(() -> {
System.out.println("Test");
});
}
TransmittableThreadLocal<String> transmittableThreadLocal = new TransmittableThreadLocal();
transmittableThreadLocal.set("23452345234");
extracted(ttlExecutor, transmittableThreadLocal);
}
private static void extracted(Executor ttlExecutor, TransmittableThreadLocal<String> transmittableThreadLocal) {
ttlExecutor.execute(() -> {
System.out.println(transmittableThreadLocal.get());
});
}
结果
点进源码看看它是怎么做的
public class TransmittableThreadLocal<T> extends InheritableThreadLocal<T> {
@Override
public final T get() {
T value = super.get();
if (null != value) {
addValue();
}
return value;
}
}
class ExecutorTtlWrapper implements Executor {
private final Executor executor;
ExecutorTtlWrapper(Executor executor) {
this.executor = executor;
}
@Override
public void execute(Runnable command) {
executor.execute(TtlRunnable.get(command));
}
}
public final class TtlRunnable implements Runnable {
private final AtomicReference<Map<TransmittableThreadLocal<?>, Object>> copiedRef;
private final Runnable runnable;
private final boolean releaseTtlValueReferenceAfterRun;
private TtlRunnable(Runnable runnable, boolean releaseTtlValueReferenceAfterRun) {
this.copiedRef = new AtomicReference<Map<TransmittableThreadLocal<?>, Object>>(TransmittableThreadLocal.copy());
this.runnable = runnable;
this.releaseTtlValueReferenceAfterRun = releaseTtlValueReferenceAfterRun;
}
public static TtlRunnable get(Runnable runnable, boolean releaseTtlValueReferenceAfterRun, boolean idempotent) {
if (null == runnable) {
return null;
}
if (runnable instanceof TtlRunnable) {
if (idempotent) {
// avoid redundant decoration, and ensure idempotency
return (TtlRunnable) runnable;
} else {
throw new IllegalStateException("Already TtlRunnable!");
}
}
return new TtlRunnable(runnable, releaseTtlValueReferenceAfterRun);
}
@Override
public void run() {
Map<TransmittableThreadLocal<?>, Object> copied = copiedRef.get();
if (copied == null || releaseTtlValueReferenceAfterRun && !copiedRef.compareAndSet(copied, null)) {
throw new IllegalStateException("TTL value reference is released after run!");
}
Map<TransmittableThreadLocal<?>, Object> backup = TransmittableThreadLocal.backupAndSetToCopied(copied);
try {
runnable.run();
} finally {
TransmittableThreadLocal.restoreBackup(backup);
}
}
}
对应TransmittableThreadLocal.backupAndSetToCopied(copied)
TransmittableThreadLocal 继承了InheritableThreadLocal方法,并维护一个全局的holder保存对应父线程的数据。 对于子线程的任务,用特殊线程池TtlExecutors执行并维护,因为里层对任务使用TtlRunnable进行增强,在执行任务之前会在全局holder中拿出对应的数据(这时候还没轮到子线程,还在父线程),再保存到当前线程的threadlocal里。