阿里TransmittableThreadLocal配合@Async使用過(guò)程
我們都知道ThreadLocal是可以在一個(gè)線程中當(dāng)容器使用的局部變量,是線程隔離、線程安全的。
但是如果子線程要獲取父線程的變量,便不太方便
我們分別來(lái)看ThreadLocal、InheritableThreadLocal、TransmittableThreadLocal區(qū)別
一、ThreadLocal
線程池配置
@Slf4j
@EnableAsync
@Configuration
public class ThreadPoolConfig {
@Bean
public Executor testExecuteAsync(){
ThreadPoolTaskExecutor poolExecutor = new ThreadPoolTaskExecutor();
poolExecutor.setCorePoolSize(5);
poolExecutor.setMaxPoolSize(10);
poolExecutor.setKeepAliveSeconds(10);
poolExecutor.setQueueCapacity(60);
poolExecutor.setThreadNamePrefix("testExecutor-");
poolExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
poolExecutor.initialize();
return poolExecutor;
}
}
ThreadLocal工具類
public class ThreadLocalContext {
private final static ThreadLocal<String> threadLocal = new ThreadLocal<>();
public static String get(){
return threadLocal.get();
}
public static void set(String data){
threadLocal.set(data);
}
public static void remove(){
threadLocal.remove();
}
}
測(cè)試service
@Service
@Slf4j
public class TestService {
@Async("testExecuteAsync")
public void test() throws InterruptedException {
log.info("父線程內(nèi)容:{}",ThreadLocalContext.get());
}
}
測(cè)試類
@Test
public void test1() throws InterruptedException {
ThreadLocalContext.set("parent:" + Thread.currentThread().getName());
for (int i = 0; i < 5; i++) {
testService.test();
}
Thread.sleep(4000);
}
運(yùn)行結(jié)果

可以看到?jīng)]有獲取到父線程內(nèi)容
二、InheritableThreadLocal
修改ThreadLocal工具類
public class ThreadLocalContext {
private final static ThreadLocal<String> threadLocal = new InheritableThreadLocal<>();
public static String get(){
return threadLocal.get();
}
public static void set(String data){
threadLocal.set(data);
}
public static void remove(){
threadLocal.remove();
}
}
運(yùn)行程序
@Test
public void test1() throws InterruptedException {
ThreadLocalContext.set("parent:" + Thread.currentThread().getName());
for (int i = 0; i < 5; i++) {
testService.test();
}
Thread.sleep(4000);
}
運(yùn)行結(jié)果

這里是可以獲取到父線程內(nèi)容的
調(diào)整TestService代碼
@Async("testExecuteAsync")
public void test() throws InterruptedException {
log.info("父線程內(nèi)容:{}",ThreadLocalContext.get());
//重新設(shè)置線程變量中的值
ThreadLocalContext.set("child:" + Thread.currentThread().getName());
}
運(yùn)行代碼
@Test
public void test1() throws InterruptedException {
ThreadLocalContext.set("parent:" + Thread.currentThread().getName());
for (int i = 0; i < 5; i++) {
testService.test();
}
Thread.sleep(4000);
//第二次調(diào)用線程獲取內(nèi)容
for (int i = 0; i < 5; i++) {
testService.test();
}
Thread.sleep(4000);
}
運(yùn)行結(jié)果

三、TransmittableThreadLocal
修改線程池配置
注意其中的TtlExecutors.getTtlExecutor( poolExecutor)是使用TTL對(duì)線程池進(jìn)行包裹
@Bean
public Executor testExecuteAsync(){
ThreadPoolTaskExecutor poolExecutor = new ThreadPoolTaskExecutor();
poolExecutor.setCorePoolSize(5);
poolExecutor.setMaxPoolSize(10);
poolExecutor.setKeepAliveSeconds(10);
poolExecutor.setQueueCapacity(60);
poolExecutor.setThreadNamePrefix("testExecutor-");
poolExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
poolExecutor.initialize();
return TtlExecutors.getTtlExecutor(poolExecutor);
}
修改threadLocal工具類
public class ThreadLocalContext {
private final static ThreadLocal<String> threadLocal = new TransmittableThreadLocal<>();
public static String get(){
return threadLocal.get();
}
public static void set(String data){
threadLocal.set(data);
}
public static void remove(){
threadLocal.remove();
}
}
運(yùn)行結(jié)果

可以看到線程每次運(yùn)行都是獲取的父線程中的內(nèi)容
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java實(shí)現(xiàn)銀行賬戶管理子系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)銀行賬戶管理子系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05
mybatis中的if?test判斷入?yún)⒌闹祮?wèn)題
這篇文章主要介紹了mybatis中的if?test判斷入?yún)⒌闹祮?wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06
Java中ArrayList和LinkedList的區(qū)別
ArrayList和LinkedList在這個(gè)方法上存在一定的性能差異,本文就介紹了Java中ArrayList和LinkedList的區(qū)別,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06
詳解如何全注解方式構(gòu)建SpringMVC項(xiàng)目
這篇文章主要介紹了詳解如何全注解方式構(gòu)建SpringMVC項(xiàng)目,利用Eclipse構(gòu)建SpringMVC項(xiàng)目,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2018-10-10
Java開(kāi)發(fā)之手把手教你搭建企業(yè)級(jí)工程SSM框架
這篇文章主要為大家介紹Java教程中搭建企業(yè)級(jí)工程SSM框架,手把手的過(guò)程操作,有需要的朋友可以借鑒參考下,希望能夠有所幫助2021-09-09
關(guān)于Java的ArrayList數(shù)組自動(dòng)擴(kuò)容機(jī)制
這篇文章主要介紹了關(guān)于Java的ArrayList數(shù)組自動(dòng)擴(kuò)容機(jī)制,ArrayList底層是基于數(shù)組實(shí)現(xiàn)的,是一個(gè)動(dòng)態(tài)數(shù)組,自動(dòng)擴(kuò)容,不是線程安全的,只能用在單線程環(huán)境下,需要的朋友可以參考下2023-05-05
Spring Boot 整合 Apache Dubbo的示例代碼
Apache Dubbo是一款高性能、輕量級(jí)的開(kāi)源 Java RPC 框架,這篇文章主要介紹了Spring Boot 整合 Apache Dubbo的方法,本文通過(guò)示例說(shuō)明給大家講解的非常詳細(xì),需要的朋友可以參考下2021-07-07

