SpringBoot父子線(xiàn)程數(shù)據(jù)傳遞的五種方案介紹
方案1.ThreadLocal+TaskDecorator
用戶(hù)工具類(lèi) UserUtils
/**
*使用ThreadLocal存儲(chǔ)共享的數(shù)據(jù)變量,如登錄的用戶(hù)信息
*/
public class UserUtils {
private static final ThreadLocal<String> userLocal=new ThreadLocal<>();
public static String getUserId(){
return userLocal.get();
}
public static void setUserId(String userId){
userLocal.set(userId);
}
public static void clear(){
userLocal.remove();
}
}自定義CustomTaskDecorator
/**
* 線(xiàn)程池修飾類(lèi)
*/
public class CustomTaskDecorator implements TaskDecorator {
@Override
public Runnable decorate(Runnable runnable) {
// 獲取主線(xiàn)程中的請(qǐng)求信息(我們的用戶(hù)信息也放在里面)
String robotId = UserUtils.getUserId();
System.out.println(robotId);
return () -> {
try {
// 將主線(xiàn)程的請(qǐng)求信息,設(shè)置到子線(xiàn)程中
UserUtils.setUserId(robotId);
// 執(zhí)行子線(xiàn)程,這一步不要忘了
runnable.run();
} finally {
// 線(xiàn)程結(jié)束,清空這些信息,否則可能造成內(nèi)存泄漏
UserUtils.clear();
}
};
}
}ExecutorConfig
在原來(lái)的基礎(chǔ)上增加 executor.setTaskDecorator(new CustomTaskDecorator());
@Bean(name = "asyncServiceExecutor")
public Executor asyncServiceExecutor() {
log.info("start asyncServiceExecutor----------------");
//ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//使用可視化運(yùn)行狀態(tài)的線(xiàn)程池
ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor();
//配置核心線(xiàn)程數(shù)
executor.setCorePoolSize(corePoolSize);
//配置最大線(xiàn)程數(shù)
executor.setMaxPoolSize(maxPoolSize);
//配置隊(duì)列大小
executor.setQueueCapacity(queueCapacity);
//配置線(xiàn)程池中的線(xiàn)程的名稱(chēng)前綴
executor.setThreadNamePrefix(namePrefix);
// rejection-policy:當(dāng)pool已經(jīng)達(dá)到max size的時(shí)候,如何處理新任務(wù)
// CALLER_RUNS:不在新線(xiàn)程中執(zhí)行任務(wù),而是有調(diào)用者所在的線(xiàn)程來(lái)執(zhí)行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//增加線(xiàn)程池修飾類(lèi)
executor.setTaskDecorator(new CustomTaskDecorator());
//增加MDC的線(xiàn)程池修飾類(lèi)
//executor.setTaskDecorator(new MDCTaskDecorator());
//執(zhí)行初始化
executor.initialize();
log.info("end asyncServiceExecutor------------");
return executor;
}AsyncServiceImpl
/**
* 使用ThreadLocal方式傳遞
* 帶有返回值
* @throws InterruptedException
*/
@Async("asyncServiceExecutor")
public CompletableFuture<String> executeValueAsync2() throws InterruptedException {
log.info("start executeValueAsync");
System.out.println("異步線(xiàn)程執(zhí)行返回結(jié)果......+");
log.info("end executeValueAsync");
return CompletableFuture.completedFuture(UserUtils.getUserId());
}Test2Controller
/**
* 使用ThreadLocal+TaskDecorator的方式
* @return
* @throws InterruptedException
* @throws ExecutionException
*/
@GetMapping("/test2")
public String test2() throws InterruptedException, ExecutionException {
UserUtils.setUserId("123456");
CompletableFuture<String> completableFuture = asyncService.executeValueAsync2();
String s = completableFuture.get();
return s;
}方案2.RequestContextHolder+TaskDecorator
自定義CustomTaskDecorator
/**
* 線(xiàn)程池修飾類(lèi)
*/
public class CustomTaskDecorator implements TaskDecorator {
@Override
public Runnable decorate(Runnable runnable) {
// 獲取主線(xiàn)程中的請(qǐng)求信息(我們的用戶(hù)信息也放在里面)
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
return () -> {
try {
// 將主線(xiàn)程的請(qǐng)求信息,設(shè)置到子線(xiàn)程中
RequestContextHolder.setRequestAttributes(attributes);
// 執(zhí)行子線(xiàn)程,這一步不要忘了
runnable.run();
} finally {
// 線(xiàn)程結(jié)束,清空這些信息,否則可能造成內(nèi)存泄漏
RequestContextHolder.resetRequestAttributes();
}
};
}
}ExecutorConfig
在原來(lái)的基礎(chǔ)上增加 executor.setTaskDecorator(new CustomTaskDecorator());
@Bean(name = "asyncServiceExecutor")
public Executor asyncServiceExecutor() {
log.info("start asyncServiceExecutor----------------");
//ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//使用可視化運(yùn)行狀態(tài)的線(xiàn)程池
ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor();
//配置核心線(xiàn)程數(shù)
executor.setCorePoolSize(corePoolSize);
//配置最大線(xiàn)程數(shù)
executor.setMaxPoolSize(maxPoolSize);
//配置隊(duì)列大小
executor.setQueueCapacity(queueCapacity);
//配置線(xiàn)程池中的線(xiàn)程的名稱(chēng)前綴
executor.setThreadNamePrefix(namePrefix);
// rejection-policy:當(dāng)pool已經(jīng)達(dá)到max size的時(shí)候,如何處理新任務(wù)
// CALLER_RUNS:不在新線(xiàn)程中執(zhí)行任務(wù),而是有調(diào)用者所在的線(xiàn)程來(lái)執(zhí)行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//增加線(xiàn)程池修飾類(lèi)
executor.setTaskDecorator(new CustomTaskDecorator());
//增加MDC的線(xiàn)程池修飾類(lèi)
//executor.setTaskDecorator(new MDCTaskDecorator());
//執(zhí)行初始化
executor.initialize();
log.info("end asyncServiceExecutor------------");
return executor;
}AsyncServiceImpl
/**
* 使用RequestAttributes獲取主線(xiàn)程傳遞的數(shù)據(jù)
* @return
* @throws InterruptedException
*/
@Async("asyncServiceExecutor")
public CompletableFuture<String> executeValueAsync3() throws InterruptedException {
log.info("start executeValueAsync");
System.out.println("異步線(xiàn)程執(zhí)行返回結(jié)果......+");
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
Object userId = attributes.getAttribute("userId", 0);
log.info("end executeValueAsync");
return CompletableFuture.completedFuture(userId.toString());
}Test2Controller
/**
* RequestContextHolder+TaskDecorator的方式
* @return
* @throws InterruptedException
* @throws ExecutionException
*/
@GetMapping("/test3")
public String test3() throws InterruptedException, ExecutionException {
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
attributes.setAttribute("userId","123456",0);
CompletableFuture<String> completableFuture = asyncService.executeValueAsync3();
String s = completableFuture.get();
return s;
}方案3.MDC+TaskDecorator
自定義MDCTaskDecorator
/**
* 線(xiàn)程池修飾類(lèi)
*/
public class MDCTaskDecorator implements TaskDecorator {
@Override
public Runnable decorate(Runnable runnable) {
// 獲取主線(xiàn)程中的請(qǐng)求信息(我們的用戶(hù)信息也放在里面)
String userId = MDC.get("userId");
Map<String, String> copyOfContextMap = MDC.getCopyOfContextMap();
System.out.println(copyOfContextMap);
return () -> {
try {
// 將主線(xiàn)程的請(qǐng)求信息,設(shè)置到子線(xiàn)程中
MDC.put("userId",userId);
// 執(zhí)行子線(xiàn)程,這一步不要忘了
runnable.run();
} finally {
// 線(xiàn)程結(jié)束,清空這些信息,否則可能造成內(nèi)存泄漏
MDC.clear();
}
};
}
}ExecutorConfig
在原來(lái)的基礎(chǔ)上增加 executor.setTaskDecorator(new MDCTaskDecorator());
@Bean(name = "asyncServiceExecutor")
public Executor asyncServiceExecutor() {
log.info("start asyncServiceExecutor----------------");
//ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//使用可視化運(yùn)行狀態(tài)的線(xiàn)程池
ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor();
//配置核心線(xiàn)程數(shù)
executor.setCorePoolSize(corePoolSize);
//配置最大線(xiàn)程數(shù)
executor.setMaxPoolSize(maxPoolSize);
//配置隊(duì)列大小
executor.setQueueCapacity(queueCapacity);
//配置線(xiàn)程池中的線(xiàn)程的名稱(chēng)前綴
executor.setThreadNamePrefix(namePrefix);
// rejection-policy:當(dāng)pool已經(jīng)達(dá)到max size的時(shí)候,如何處理新任務(wù)
// CALLER_RUNS:不在新線(xiàn)程中執(zhí)行任務(wù),而是有調(diào)用者所在的線(xiàn)程來(lái)執(zhí)行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//增加MDC的線(xiàn)程池修飾類(lèi)
executor.setTaskDecorator(new MDCTaskDecorator());
//執(zhí)行初始化
executor.initialize();
log.info("end asyncServiceExecutor------------");
return executor;
}AsyncServiceImpl
/**
* 使用MDC獲取主線(xiàn)程傳遞的數(shù)據(jù)
* @return
* @throws InterruptedException
*/
@Async("asyncServiceExecutor")
public CompletableFuture<String> executeValueAsync5() throws InterruptedException {
log.info("start executeValueAsync");
System.out.println("異步線(xiàn)程執(zhí)行返回結(jié)果......+");
log.info("end executeValueAsync");
return CompletableFuture.completedFuture(MDC.get("userId"));
}Test2Controller
/**
* 使用MDC+TaskDecorator方式
* 本質(zhì)也是ThreadLocal+TaskDecorator方式
* @return
* @throws InterruptedException
* @throws ExecutionException
*/
@GetMapping("/test5")
public String test5() throws InterruptedException, ExecutionException {
MDC.put("userId","123456");
CompletableFuture<String> completableFuture = asyncService.executeValueAsync5();
String s = completableFuture.get();
return s;
}方案4.InheritableThreadLocal
用戶(hù)工具類(lèi) UserInheritableUtils
//**
*使用InheritableThreadLocal存儲(chǔ)線(xiàn)程之間共享的數(shù)據(jù)變量,如登錄的用戶(hù)信息
*/
public class UserInheritableUtils {
private static final InheritableThreadLocal<String> userLocal=new InheritableThreadLocal<>();
public static String getUserId(){
return userLocal.get();
}
public static void setUserId(String userId){
userLocal.set(userId);
}
public static void clear(){
userLocal.remove();
}
}AsyncServiceImpl
/**
* 使用InheritableThreadLocal獲取主線(xiàn)程傳遞的數(shù)據(jù)
* @return
* @throws InterruptedException
*/
@Async("asyncServiceExecutor")
public CompletableFuture<String> executeValueAsync4() throws InterruptedException {
log.info("start executeValueAsync");
System.out.println("異步線(xiàn)程執(zhí)行返回結(jié)果......+");
log.info("end executeValueAsync");
return CompletableFuture.completedFuture(UserInheritableUtils.getUserId());
}Test2Controller
/**
* 使用InheritableThreadLocal方式
* @return
* @throws InterruptedException
* @throws ExecutionException
*/
@GetMapping("/test4")
public String test4(@RequestParam("userId") String userId) throws InterruptedException, ExecutionException {
UserInheritableUtils.setUserId(userId);
CompletableFuture<String> completableFuture = asyncService.executeValueAsync4();
String s = completableFuture.get();
return s;
}方案5.TransmittableThreadLocal
用戶(hù)工具類(lèi) UserTransmittableUtils
/**
*使用TransmittableThreadLocal存儲(chǔ)線(xiàn)程之間共享的數(shù)據(jù)變量,如登錄的用戶(hù)信息
*/
public class UserTransmittableUtils {
private static final TransmittableThreadLocal<String> userLocal=new TransmittableThreadLocal<>();
public static String getUserId(){
return userLocal.get();
}
public static void setUserId(String userId){
userLocal.set(userId);
}
public static void clear(){
userLocal.remove();
}
}
}AsyncServiceImpl
/**
* 使用TransmittableThreadLocal獲取主線(xiàn)程傳遞的數(shù)據(jù)
* @return
* @throws InterruptedException
*/
@Async("asyncServiceExecutor")
public CompletableFuture<String> executeValueAsync6() throws InterruptedException {
log.info("start executeValueAsync");
System.out.println("異步線(xiàn)程執(zhí)行返回結(jié)果......+");
log.info("end executeValueAsync");
return CompletableFuture.completedFuture(UserTransmittableUtils.getUserId());
}Test2Controller
/**
* 使用TransmittableThreadLocal方式
* @return
* @throws InterruptedException
* @throws ExecutionException
*/
@GetMapping("/test6")
public String test6() throws InterruptedException, ExecutionException {
UserTransmittableUtils.setUserId("123456");
CompletableFuture<String> completableFuture = asyncService.executeValueAsync6();
String s = completableFuture.get();
return s;
}maven依賴(lài)
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>transmittable-thread-local</artifactId>
<version>2.12.1</version>
</dependency>方案對(duì)比
方案1,方案2,方案3主要是借助TaskDecorator進(jìn)行父子線(xiàn)程之間傳遞數(shù)據(jù)。其中MDC方案主要借鑒于MDC的日志跟蹤的思想來(lái)實(shí)現(xiàn),關(guān)于MDC相關(guān)的日志跟蹤后續(xù)會(huì)學(xué)習(xí)分享
方案4和方案5使用InheritableThreadLocal和TransmittableThreadLocal來(lái)實(shí)現(xiàn),其中TransmittableThreadLocal是阿里InheritableThreadLocal進(jìn)行優(yōu)化封裝。
本人推薦使用方案5,哈哈。
簡(jiǎn)答說(shuō)一下InheritableThreadLocal
public static void main(String[] args) {
ThreadPoolExecutor executor = new ThreadPoolExecutor(1,1,1,
TimeUnit.MINUTES,new ArrayBlockingQueue<>(1));
ThreadLocal local = new InheritableThreadLocal();
local.set(1);
executor.execute(()->{
System.out.println("打印1:"+local.get());
});
local.set(2);
System.out.println("打印2:"+local.get());
executor.execute(()->{
System.out.println("打印3:"+local.get());
});
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("打印4:"+local.get());
}
}).start();
}運(yùn)行結(jié)果如下
打印2:2
打印1:1
打印3:1
打印4:2
分析: 分析打印3為什么是1,InheritableThreadLocal的繼承性是在new Thread創(chuàng)建子線(xiàn)程時(shí)候在構(gòu)造函數(shù)內(nèi)把父線(xiàn)程內(nèi)線(xiàn)程變量拷貝到子線(xiàn)程內(nèi)部的。 為了不在創(chuàng)建新線(xiàn)程耗費(fèi)資源,我們一般會(huì)用線(xiàn)程池,線(xiàn)程池的線(xiàn)程會(huì)復(fù)用,那么線(xiàn)程中的ThreadLocal便不對(duì)了,可能是舊的,因?yàn)榫€(xiàn)程是舊的。
總結(jié)
上面的的方案你學(xué)會(huì)了么
到此這篇關(guān)于SpringBoot父子線(xiàn)程數(shù)據(jù)傳遞的五種方案介紹的文章就介紹到這了,更多相關(guān)SpringBoot數(shù)據(jù)傳遞內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java Socket編程(三) 服務(wù)器Sockets
Java Socket編程(三) 服務(wù)器Sockets...2006-12-12
JVM內(nèi)存結(jié)構(gòu)劃分實(shí)例解析
這篇文章主要介紹了JVM內(nèi)存結(jié)構(gòu)劃分實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-12-12
SpringBoot+阿里云OSS實(shí)現(xiàn)在線(xiàn)視頻播放的示例
這篇文章主要介紹了SpringBoot+阿里云OSS實(shí)現(xiàn)在線(xiàn)視頻播放的示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11
Java使用正則表達(dá)式檢索、替換String中特定字符和正則表達(dá)式的一切
這篇文章主要給大家介紹了關(guān)于Java使用正則表達(dá)式檢索、替換String中特定字符和正則表達(dá)式的一切,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
java實(shí)現(xiàn)獲取用戶(hù)的MAC地址
本文給大家匯總介紹了下使用java實(shí)現(xiàn)獲取客戶(hù)端用戶(hù)的MAC地址的方法,當(dāng)然最后一種更全面一些,有需要的小伙伴們可以根據(jù)需求自由選擇。2015-10-10
Spring-Boot 訪(fǎng)問(wèn)外部接口的方案總結(jié)
在Spring-Boot項(xiàng)目開(kāi)發(fā)中,存在著本模塊的代碼需要訪(fǎng)問(wèn)外面模塊接口,或外部url鏈接的需求,針對(duì)這一需求目前存在著三種解決方案,下面將對(duì)這三種方案進(jìn)行整理和說(shuō)明,對(duì)Spring-Boot 訪(fǎng)問(wèn)外部接口方案感興趣的朋友跟隨小編一起看看吧2022-12-12
如何使用 Spring Boot 和 Canal 實(shí)現(xiàn) My
本文介紹了如何使用SpringBoot和Canal實(shí)現(xiàn)MySQL數(shù)據(jù)庫(kù)之間的數(shù)據(jù)同步,通過(guò)配置主庫(kù)、創(chuàng)建Canal用戶(hù)、配置CanalServer以及開(kāi)發(fā)SpringBoot客戶(hù)端,實(shí)現(xiàn)了將主庫(kù)的數(shù)據(jù)實(shí)時(shí)同步到多個(gè)從庫(kù),感興趣的朋友跟隨小編一起看看吧2025-02-02

