SpringBoot父子線程數(shù)據(jù)傳遞的五種方案介紹
方案1.ThreadLocal+TaskDecorator
用戶工具類 UserUtils
/** *使用ThreadLocal存儲共享的數(shù)據(jù)變量,如登錄的用戶信息 */ 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
/** * 線程池修飾類 */ public class CustomTaskDecorator implements TaskDecorator { @Override public Runnable decorate(Runnable runnable) { // 獲取主線程中的請求信息(我們的用戶信息也放在里面) String robotId = UserUtils.getUserId(); System.out.println(robotId); return () -> { try { // 將主線程的請求信息,設(shè)置到子線程中 UserUtils.setUserId(robotId); // 執(zhí)行子線程,這一步不要忘了 runnable.run(); } finally { // 線程結(jié)束,清空這些信息,否則可能造成內(nèi)存泄漏 UserUtils.clear(); } }; } }
ExecutorConfig
在原來的基礎(chǔ)上增加 executor.setTaskDecorator(new CustomTaskDecorator());
@Bean(name = "asyncServiceExecutor") public Executor asyncServiceExecutor() { log.info("start asyncServiceExecutor----------------"); //ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); //使用可視化運(yùn)行狀態(tài)的線程池 ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor(); //配置核心線程數(shù) executor.setCorePoolSize(corePoolSize); //配置最大線程數(shù) executor.setMaxPoolSize(maxPoolSize); //配置隊(duì)列大小 executor.setQueueCapacity(queueCapacity); //配置線程池中的線程的名稱前綴 executor.setThreadNamePrefix(namePrefix); // rejection-policy:當(dāng)pool已經(jīng)達(dá)到max size的時候,如何處理新任務(wù) // CALLER_RUNS:不在新線程中執(zhí)行任務(wù),而是有調(diào)用者所在的線程來執(zhí)行 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); //增加線程池修飾類 executor.setTaskDecorator(new CustomTaskDecorator()); //增加MDC的線程池修飾類 //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("異步線程執(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
/** * 線程池修飾類 */ public class CustomTaskDecorator implements TaskDecorator { @Override public Runnable decorate(Runnable runnable) { // 獲取主線程中的請求信息(我們的用戶信息也放在里面) RequestAttributes attributes = RequestContextHolder.getRequestAttributes(); return () -> { try { // 將主線程的請求信息,設(shè)置到子線程中 RequestContextHolder.setRequestAttributes(attributes); // 執(zhí)行子線程,這一步不要忘了 runnable.run(); } finally { // 線程結(jié)束,清空這些信息,否則可能造成內(nèi)存泄漏 RequestContextHolder.resetRequestAttributes(); } }; } }
ExecutorConfig
在原來的基礎(chǔ)上增加 executor.setTaskDecorator(new CustomTaskDecorator());
@Bean(name = "asyncServiceExecutor") public Executor asyncServiceExecutor() { log.info("start asyncServiceExecutor----------------"); //ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); //使用可視化運(yùn)行狀態(tài)的線程池 ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor(); //配置核心線程數(shù) executor.setCorePoolSize(corePoolSize); //配置最大線程數(shù) executor.setMaxPoolSize(maxPoolSize); //配置隊(duì)列大小 executor.setQueueCapacity(queueCapacity); //配置線程池中的線程的名稱前綴 executor.setThreadNamePrefix(namePrefix); // rejection-policy:當(dāng)pool已經(jīng)達(dá)到max size的時候,如何處理新任務(wù) // CALLER_RUNS:不在新線程中執(zhí)行任務(wù),而是有調(diào)用者所在的線程來執(zhí)行 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); //增加線程池修飾類 executor.setTaskDecorator(new CustomTaskDecorator()); //增加MDC的線程池修飾類 //executor.setTaskDecorator(new MDCTaskDecorator()); //執(zhí)行初始化 executor.initialize(); log.info("end asyncServiceExecutor------------"); return executor; }
AsyncServiceImpl
/** * 使用RequestAttributes獲取主線程傳遞的數(shù)據(jù) * @return * @throws InterruptedException */ @Async("asyncServiceExecutor") public CompletableFuture<String> executeValueAsync3() throws InterruptedException { log.info("start executeValueAsync"); System.out.println("異步線程執(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
/** * 線程池修飾類 */ public class MDCTaskDecorator implements TaskDecorator { @Override public Runnable decorate(Runnable runnable) { // 獲取主線程中的請求信息(我們的用戶信息也放在里面) String userId = MDC.get("userId"); Map<String, String> copyOfContextMap = MDC.getCopyOfContextMap(); System.out.println(copyOfContextMap); return () -> { try { // 將主線程的請求信息,設(shè)置到子線程中 MDC.put("userId",userId); // 執(zhí)行子線程,這一步不要忘了 runnable.run(); } finally { // 線程結(jié)束,清空這些信息,否則可能造成內(nèi)存泄漏 MDC.clear(); } }; } }
ExecutorConfig
在原來的基礎(chǔ)上增加 executor.setTaskDecorator(new MDCTaskDecorator());
@Bean(name = "asyncServiceExecutor") public Executor asyncServiceExecutor() { log.info("start asyncServiceExecutor----------------"); //ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); //使用可視化運(yùn)行狀態(tài)的線程池 ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor(); //配置核心線程數(shù) executor.setCorePoolSize(corePoolSize); //配置最大線程數(shù) executor.setMaxPoolSize(maxPoolSize); //配置隊(duì)列大小 executor.setQueueCapacity(queueCapacity); //配置線程池中的線程的名稱前綴 executor.setThreadNamePrefix(namePrefix); // rejection-policy:當(dāng)pool已經(jīng)達(dá)到max size的時候,如何處理新任務(wù) // CALLER_RUNS:不在新線程中執(zhí)行任務(wù),而是有調(diào)用者所在的線程來執(zhí)行 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); //增加MDC的線程池修飾類 executor.setTaskDecorator(new MDCTaskDecorator()); //執(zhí)行初始化 executor.initialize(); log.info("end asyncServiceExecutor------------"); return executor; }
AsyncServiceImpl
/** * 使用MDC獲取主線程傳遞的數(shù)據(jù) * @return * @throws InterruptedException */ @Async("asyncServiceExecutor") public CompletableFuture<String> executeValueAsync5() throws InterruptedException { log.info("start executeValueAsync"); System.out.println("異步線程執(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
用戶工具類 UserInheritableUtils
//** *使用InheritableThreadLocal存儲線程之間共享的數(shù)據(jù)變量,如登錄的用戶信息 */ 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獲取主線程傳遞的數(shù)據(jù) * @return * @throws InterruptedException */ @Async("asyncServiceExecutor") public CompletableFuture<String> executeValueAsync4() throws InterruptedException { log.info("start executeValueAsync"); System.out.println("異步線程執(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
用戶工具類 UserTransmittableUtils
/** *使用TransmittableThreadLocal存儲線程之間共享的數(shù)據(jù)變量,如登錄的用戶信息 */ 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獲取主線程傳遞的數(shù)據(jù) * @return * @throws InterruptedException */ @Async("asyncServiceExecutor") public CompletableFuture<String> executeValueAsync6() throws InterruptedException { log.info("start executeValueAsync"); System.out.println("異步線程執(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依賴
<dependency> <groupId>com.alibaba</groupId> <artifactId>transmittable-thread-local</artifactId> <version>2.12.1</version> </dependency>
方案對比
方案1,方案2,方案3主要是借助TaskDecorator進(jìn)行父子線程之間傳遞數(shù)據(jù)。其中MDC方案主要借鑒于MDC的日志跟蹤的思想來實(shí)現(xiàn),關(guān)于MDC相關(guān)的日志跟蹤后續(xù)會學(xué)習(xí)分享
方案4和方案5使用InheritableThreadLocal和TransmittableThreadLocal來實(shí)現(xiàn),其中TransmittableThreadLocal是阿里InheritableThreadLocal進(jìn)行優(yōu)化封裝。
本人推薦使用方案5,哈哈。
簡答說一下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)建子線程時候在構(gòu)造函數(shù)內(nèi)把父線程內(nèi)線程變量拷貝到子線程內(nèi)部的。 為了不在創(chuàng)建新線程耗費(fèi)資源,我們一般會用線程池,線程池的線程會復(fù)用,那么線程中的ThreadLocal便不對了,可能是舊的,因?yàn)榫€程是舊的。
總結(jié)
上面的的方案你學(xué)會了么
到此這篇關(guān)于SpringBoot父子線程數(shù)據(jù)傳遞的五種方案介紹的文章就介紹到這了,更多相關(guān)SpringBoot數(shù)據(jù)傳遞內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
如何對?Excel?表格中提取的數(shù)據(jù)進(jìn)行批量更新
這篇文章主要介紹了如何對Excel表格中提取的數(shù)據(jù)進(jìn)行批量更新操作,本文通過示例代碼介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧2024-06-06java中httpclient封裝post請求和get的請求實(shí)例
這篇文章主要介紹了java中httpclient封裝post請求和get的請求實(shí)例,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10IDEA 2020 無法啟動的解決辦法(啟動崩盤)附IDEA 2020 新功能
這篇文章主要介紹了IDEA 2020 無法啟動的解決辦法(啟動崩盤)附IDEA 2020 新功能,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-04-04Java實(shí)現(xiàn)Map集合二級聯(lián)動示例
Java實(shí)現(xiàn)Map集合二級聯(lián)動示例,需要的朋友可以參考下2014-03-03