日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

SpringBoot - 优雅的实现【异步编程】

發布時間:2025/3/21 javascript 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SpringBoot - 优雅的实现【异步编程】 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 概述
  • V1.0 默認的實現
    • Step1 搞配置類,開啟@EnableAsync
    • Step2 搞方法標記 @Async注解
    • Step3 搞調用
  • Spring提供的線程池
  • V2.0 實現@Async的自定義線程池
  • V3.0 多個線程池處理
    • 多個線程池
    • 默認線程池
    • 驗證一把
  • 源碼


概述

Spring3開始提供了@Async注解,我們只需要在方法上標注此注解,此方法即可實現異步調用。 除此之外, 還得需要一個配置類,通過@EnableAsync 來開啟異步功能 。


V1.0 默認的實現

Step1 搞配置類,開啟@EnableAsync

我們需要使用@EnableAsync來開啟異步任務支持。

@EnableAsync注解可以直接放在SpringBoot啟動類上,也可以單獨放在其他配置類上。

我們這里選擇單獨搞個配置類

@Configuration @EnableAsync public class ThreadPoolTaskConfig {}


Step2 搞方法標記 @Async注解

package com.artisan.jobs;import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component;/*** @author 小工匠* @version 1.0* @description: TODO* @date 2022/3/1 0:42* @mark: show me the code , change the world*/@Component @Slf4j public class AsyncJob {@Async public void job1() throws InterruptedException {long beginTime = System.currentTimeMillis();Thread.sleep(2000);long endTime = System.currentTimeMillis();log.info("job1 cost {} ms", endTime - beginTime);}@Async public void job2() throws InterruptedException {long beginTime = System.currentTimeMillis();Thread.sleep(2000);long endTime = System.currentTimeMillis();log.info("job2 cost {} ms", endTime - beginTime);} }


Step3 搞調用

package com.artisan.controller;import com.artisan.jobs.AsyncJob; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;/*** @author 小工匠* @version 1.0* @description: TODO* @date 2022/3/1 0:44* @mark: show me the code , change the world*/@RestController @RequestMapping("/async") @Slf4j public class AsyncController {@Autowiredprivate AsyncJob asyncJob;@RequestMapping("/job")public String task() throws InterruptedException {long beginTime = System.currentTimeMillis();// 執行異步任務asyncJob.job1();asyncJob.job2();// 模擬業務耗時Thread.sleep(1000);long cost = System.currentTimeMillis() - beginTime;log.info("main cost {} ms", cost);return "Task Cost " + cost + " ms";} }

@Async注解在默認情況下用的是SimpleAsyncTaskExecutor線,不是真正意義上的線程池。



所以,線程名稱是 task-1 , task-2, task-3 , task-4…

2022-03-02 22:33:47.007 [http-nio-8080-exec-6] INFO com.artisan.controller.AsyncController:39 - main cost 1001 ms 2022-03-02 22:33:47.675 [http-nio-8080-exec-2] INFO com.artisan.controller.AsyncController:39 - main cost 1001 ms 2022-03-02 22:33:48.021 [task-4] INFO com.artisan.jobs.AsyncJob:35 - job2 cost 2014 ms 2022-03-02 22:33:48.021 [task-3] INFO com.artisan.jobs.AsyncJob:26 - job1 cost 2014 ms 2022-03-02 22:33:48.396 [http-nio-8080-exec-5] INFO com.artisan.controller.AsyncController:39 - main cost 1015 ms 2022-03-02 22:33:48.678 [task-6] INFO com.artisan.jobs.AsyncJob:35 - job2 cost 2004 ms 2022-03-02 22:33:48.678 [task-5] INFO com.artisan.jobs.AsyncJob:26 - job1 cost 2004 ms 2022-03-02 22:33:49.004 [http-nio-8080-exec-3] INFO com.artisan.controller.AsyncController:39 - main cost 1008 ms 2022-03-02 22:33:49.393 [task-8] INFO com.artisan.jobs.AsyncJob:35 - job2 cost 2011 ms 2022-03-02 22:33:49.393 [task-7] INFO com.artisan.jobs.AsyncJob:26 - job1 cost 2011 ms 2022-03-02 22:33:50.012 [task-9] INFO com.artisan.jobs.AsyncJob:26 - job1 cost 2015 ms 2022-03-02 22:33:50.012 [task-10] INFO com.artisan.jobs.AsyncJob:35 - job2 cost 2015 ms

可以看到,每次調用都會new一個線程。若系統中不斷的創建線程…


Spring提供的線程池

名稱說明
SimpleAsyncTaskExecutor這個類沒有實現異步調用,只是一個同步操作。只適用于不需要多線程的地
ConcurrentTaskExecutorExecutor的適配類,不推薦使用。如ThreadPoolTaskExecutor不滿足要求時,才用考慮使用這個類
ThreadPoolTaskScheduler可以使用cron表達式
ThreadPoolTaskExecutor推薦。 是對java.util.concurrent.ThreadPoolExecutor的包裝


V2.0 實現@Async的自定義線程池

package com.artisan.config;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.ThreadPoolExecutor;/*** @author 小工匠* @version 1.0* @description: 使用@EnableAsync來開啟異步任務支持,@EnableAsync注解可以直接放在SpringBoot啟動類上,也可以單獨放在其他配置類上。* 我們這里選擇使用單獨的配置類AsyncConfiguration。* @date 2022/3/1 0:41* @mark: show me the code , change the world*/@Configuration @EnableAsync public class ThreadPoolTaskConfig {/*** 核心線程數(默認線程數)*/private static final int CORE_POOL_SIZE = 5;/*** 最大線程數*/private static final int MAX_POOL_SIZE = 10;/*** 允許線程空閑時間(單位:默認為秒)*/private static final int KEEP_ALIVE_TIME = 10;/*** 緩沖隊列大小*/private static final int QUEUE_CAPACITY = 200;/*** 線程池名前綴*/private static final String THREAD_NAME_PREFIX = "Async-Service-";/*** 自定義線程池** @return*/@Bean("customAsyncPoolTaskExecutor")public ThreadPoolTaskExecutor taskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(CORE_POOL_SIZE);executor.setMaxPoolSize(MAX_POOL_SIZE);executor.setQueueCapacity(KEEP_ALIVE_TIME);executor.setKeepAliveSeconds(QUEUE_CAPACITY);executor.setThreadNamePrefix(THREAD_NAME_PREFIX);/*** 當線程池的任務緩存隊列已滿并且線程池中的線程數目達到maximumPoolSize,如果還有任務到來就會采取任務拒絕策略* 通常有以下四種策略:* ThreadPoolExecutor.AbortPolicy:丟棄任務并拋出RejectedExecutionException異常。* ThreadPoolExecutor.DiscardPolicy:丟棄任務,但是不拋出異常。* ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務,然后重新嘗試執行任務(重復此過程)* ThreadPoolExecutor.CallerRunsPolicy:重試添加當前的任務,自動重復調用 execute() 方法,直到成功*/executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());executor.initialize();return executor;}}

其他保持不變, 重啟測試


V3.0 多個線程池處理

需求: 不同的業務,使用不同的線程池

多個線程池

package com.artisan.config;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.ThreadPoolExecutor;/*** @author 小工匠* @version 1.0* @description: 使用@EnableAsync來開啟異步任務支持,@EnableAsync注解可以直接放在SpringBoot啟動類上,也可以單獨放在其他配置類上。* 我們這里選擇使用單獨的配置類ThreadPoolTaskConfig* @date 2022/3/1 0:41* @mark: show me the code , change the world*/@Configuration @EnableAsync public class ThreadPoolTaskConfig {/*** 核心線程數(默認線程數)*/private static final int CORE_POOL_SIZE = 5;/*** 最大線程數*/private static final int MAX_POOL_SIZE = 10;/*** 允許線程空閑時間(單位:默認為秒)*/private static final int KEEP_ALIVE_TIME = 10;/*** 緩沖隊列大小*/private static final int QUEUE_CAPACITY = 200;/*** 線程池名前綴*/private static final String THREAD_NAME_PREFIX = "Biz1_Async-Service-";/*** 線程池名前綴*/private static final String THREAD_NAME_PREFIX_2= "Biz2_Async-Service-";/*** 自定義線程池** @return*/@Bean("tp1")public ThreadPoolTaskExecutor taskExecutor() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(CORE_POOL_SIZE);executor.setMaxPoolSize(MAX_POOL_SIZE);executor.setQueueCapacity(KEEP_ALIVE_TIME);executor.setKeepAliveSeconds(QUEUE_CAPACITY);executor.setThreadNamePrefix(THREAD_NAME_PREFIX);/*** 當線程池的任務緩存隊列已滿并且線程池中的線程數目達到maximumPoolSize,如果還有任務到來就會采取任務拒絕策略* 通常有以下四種策略:* ThreadPoolExecutor.AbortPolicy:丟棄任務并拋出RejectedExecutionException異常。* ThreadPoolExecutor.DiscardPolicy:丟棄任務,但是不拋出異常。* ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務,然后重新嘗試執行任務(重復此過程)* ThreadPoolExecutor.CallerRunsPolicy:重試添加當前的任務,自動重復調用 execute() 方法,直到成功*/executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());executor.initialize();return executor;}/*** 自定義線程池** @return*/@Bean("tp2")public ThreadPoolTaskExecutor taskExecutor2() {ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();executor.setCorePoolSize(CORE_POOL_SIZE);executor.setMaxPoolSize(MAX_POOL_SIZE);executor.setQueueCapacity(KEEP_ALIVE_TIME);executor.setKeepAliveSeconds(QUEUE_CAPACITY);executor.setThreadNamePrefix(THREAD_NAME_PREFIX_2);/*** 當線程池的任務緩存隊列已滿并且線程池中的線程數目達到maximumPoolSize,如果還有任務到來就會采取任務拒絕策略* 通常有以下四種策略:* ThreadPoolExecutor.AbortPolicy:丟棄任務并拋出RejectedExecutionException異常。* ThreadPoolExecutor.DiscardPolicy:丟棄任務,但是不拋出異常。* ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務,然后重新嘗試執行任務(重復此過程)* ThreadPoolExecutor.CallerRunsPolicy:重試添加當前的任務,自動重復調用 execute() 方法,直到成功*/executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());executor.initialize();return executor;}}

配置 多個線程池, 然后 為@Async指定線程池名字即可實現 多個線程池處理

package com.artisan.jobs;import lombok.extern.slf4j.Slf4j; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component;/*** @author 小工匠* @version 1.0* @description: TODO* @date 2022/3/1 0:42* @mark: show me the code , change the world*/@Component @Slf4j public class AsyncJob {@Async("tp1")public void job1() throws InterruptedException {long beginTime = System.currentTimeMillis();Thread.sleep(2000);long endTime = System.currentTimeMillis();log.info("job1 cost {} ms", endTime - beginTime);}@Async("tp2")public void job2() throws InterruptedException {long beginTime = System.currentTimeMillis();Thread.sleep(2000);long endTime = System.currentTimeMillis();log.info("job2 cost {} ms", endTime - beginTime);}@Async()public void job3() throws InterruptedException {long beginTime = System.currentTimeMillis();Thread.sleep(2000);long endTime = System.currentTimeMillis();log.info("job3 cost {} ms", endTime - beginTime);} }

默認線程池

@Async()沒標注,用哪個?????? 當系統存在多個線程池時,我們也可以配置一個默認線程池 ,配置類讓其實現AsyncConfigurer,并重寫getAsyncExecutor()方法,指定默認線程池

package com.artisan.multi;import lombok.extern.slf4j.Slf4j; import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.AsyncConfigurer; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;import java.util.concurrent.Executor; import java.util.concurrent.ThreadPoolExecutor;/*** @author 小工匠* @version 1.0* @mark: show me the code , change the world* <p>* 實現AsyncConfigurer,并重寫getAsyncExecutor()方法,指定默認線程池*/@Configuration @EnableAsync @Slf4j public class DefaultAsyncConfiguration implements AsyncConfigurer {/*** 核心線程數(默認線程數)*/private static final int CORE_POOL_SIZE = 2;/*** 最大線程數*/private static final int MAX_POOL_SIZE = 10;/*** 允許線程空閑時間(單位:默認為秒)*/private static final int KEEP_ALIVE_TIME = 10;/*** 緩沖隊列大小*/private static final int QUEUE_CAPACITY = 200;/*** 線程池名前綴*/private static final String THREAD_NAME_PREFIX = "Default_Async-Service-";@Bean(name = "defaultPool")public ThreadPoolTaskExecutor executor() {ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();taskExecutor.setCorePoolSize(CORE_POOL_SIZE);taskExecutor.setMaxPoolSize(MAX_POOL_SIZE);taskExecutor.setQueueCapacity(KEEP_ALIVE_TIME);taskExecutor.setKeepAliveSeconds(QUEUE_CAPACITY);taskExecutor.setThreadNamePrefix(THREAD_NAME_PREFIX);/*** 當線程池的任務緩存隊列已滿并且線程池中的線程數目達到maximumPoolSize,如果還有任務到來就會采取任務拒絕策略* 通常有以下四種策略:* ThreadPoolExecutor.AbortPolicy:丟棄任務并拋出RejectedExecutionException異常。* ThreadPoolExecutor.DiscardPolicy:丟棄任務,但是不拋出異常。* ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務,然后重新嘗試執行任務(重復此過程)* ThreadPoolExecutor.CallerRunsPolicy:重試添加當前的任務,自動重復調用 execute() 方法,直到成功*/taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());taskExecutor.initialize();return taskExecutor;}/*** 指定默認線程池*/@Overridepublic Executor getAsyncExecutor() {return executor();}@Overridepublic AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {return (ex, method, params) -> log.error("線程池執行任務發橫未知錯誤,執行方法:{}", method.getName(), ex);}}

驗證一把

@RestController @RequestMapping("/async") @Slf4j public class AsyncController {@Autowiredprivate AsyncJob asyncJob;@RequestMapping("/job")public String task() throws InterruptedException {long beginTime = System.currentTimeMillis();// 執行異步任務asyncJob.job1();asyncJob.job2();asyncJob.job3();// 模擬業務耗時Thread.sleep(1000);long cost = System.currentTimeMillis() - beginTime;log.info("main cost {} ms", cost);return "Task Cost " + cost + " ms";} }

完美匹配…


源碼

https://github.com/yangshangwei/boot2

總結

以上是生活随笔為你收集整理的SpringBoot - 优雅的实现【异步编程】的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。