TransmittableThreadLocal ---传递性的threadLocal

225 阅读1分钟

大家都知道,子线程获取父线程的共享数据,可以通过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());  
            });  
        }  
  
    }
}    

image.png

竟然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());  
            });  
    }

结果

image.png

点进源码看看它是怎么做的

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) image.png

TransmittableThreadLocal 继承了InheritableThreadLocal方法,并维护一个全局的holder保存对应父线程的数据。 对于子线程的任务,用特殊线程池TtlExecutors执行并维护,因为里层对任务使用TtlRunnable进行增强,在执行任务之前会在全局holder中拿出对应的数据(这时候还没轮到子线程,还在父线程),再保存到当前线程的threadlocal里。