https://blog.csdn.net/weixin_44637711/article/details/123698016
(面试题:如何在子线程拿到父线程threadLocal的值)
/**
* 直接使用ThreadLocal,无法获得父线程的值
*/
public static void demo1() {
ThreadLocal<String> stringThreadLocal = new ThreadLocal<>();
stringThreadLocal.set("今天星期五");
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + stringThreadLocal.get());//Thread-0null
}).start();
System.out.println(Thread.currentThread().getName() + "执行完成");
}
/**
* 使用InheritableThreadLocal,可以拿到父线程的值,
* 原理:在线程init方法时传入父线程的threadLocal
*/
public static void demo2() {
ThreadLocal<String> stringThreadLocal = new InheritableThreadLocal<>();
stringThreadLocal.set("今天星期五");
new Thread(() -> {
System.out.println(Thread.currentThread().getName()
+ stringThreadLocal.get());//Thread-0今天星期五
}).start();
System.out.println(Thread.currentThread().getName() + "执行完成");
}
/**
* 在线程池使用InheritableThreadLocal,因为线程池中的线程是重复利用的,只能拿到线程init时父线程ThreadLocal的值
*
* @throws InterruptedException
*/
public static void demo3() throws InterruptedException {
InheritableThreadLocal<String> threadLocal = new InheritableThreadLocal<>();
ExecutorService threadPool = Executors.newFixedThreadPool(1);
threadLocal.set("首次赋值");
Semaphore semaphore = new Semaphore(1);
threadPool.submit(() -> {
System.out.println(Thread.currentThread().getName() + threadLocal.get());
});
semaphore.acquire();
threadLocal.set("再次赋值");
threadPool.submit(() -> {
semaphore.release();
System.out.println(Thread.currentThread().getName()
+ threadLocal.get());//还是初值
});
semaphore.acquire();
threadPool.shutdown();
}
通过装饰类调用前重新将父线程的值进行赋值
/**
* 注意:
* 即使是同一个Runnable任务多次提交到线程池时,
* 每次提交时都需要通过修饰操作(即TtlRunnable.get(task))以抓取这次提交时的
* TransmittableThreadLocal上下文的值;
* 即如果同一个任务下一次提交时不执行修饰而仍然使用上一次的TtlRunnable,
* 则提交的任务运行时会是之前修饰操作所抓取的上下文。
*
* @throws InterruptedException
*/
public static void demo4() throws InterruptedException {
TransmittableThreadLocal<String> threadLocal = new TransmittableThreadLocal<>();
ExecutorService threadPool = Executors.newFixedThreadPool(1);
threadLocal.set("首次赋值");
Semaphore semaphore = new Semaphore(1);
// 额外的处理,生成修饰了的对象ttlRunnable
Runnable task = TtlRunnable.get(() -> {
System.out.println(Thread.currentThread().getName() + threadLocal.get());
});
threadPool.submit(task);//pool-1-thread-1首次赋值
semaphore.acquire();
threadLocal.remove();
threadLocal.set("再次赋值");
// 额外的处理,生成修饰了的对象ttlCallable
Runnable task2 = TtlRunnable.get(() -> {
System.out.println(Thread.currentThread().getName() + threadLocal.get());
});
threadPool.submit(task2);//pool-1-thread-1再次赋值
semaphore.acquire();
threadPool.shutdown();
}
/**
* 修饰线程池
* 省去每次Runnable和Callable传入线程池时的修饰,这个逻辑可以在线程池中完成。
*
* @throws InterruptedException
*/
public static void demo5() throws InterruptedException {
TransmittableThreadLocal<String> threadLocal = new TransmittableThreadLocal<>();
ExecutorService executorService = Executors.newFixedThreadPool(1);
ExecutorService threadPool = TtlExecutors.getTtlExecutorService(executorService);
threadLocal.set("首次赋值");
Semaphore semaphore = new Semaphore(1);
threadPool.submit(() -> {
System.out.println(Thread.currentThread().getName() + threadLocal.get());
});
semaphore.acquire();
threadLocal.set("再次赋值");
threadPool.submit(() -> {
semaphore.release();
System.out.println(Thread.currentThread().getName() + threadLocal.get());//pool-1-thread-1再次赋值
});
semaphore.acquire();
threadPool.shutdown();
}
附:maven地址
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>2.12.6</version>
</dependency>