SpringBoot應用程式中需要新增@EnableAsync註解,來開啟非同步調用,一般也會配置一個執行緒池,非同步的方法交給特定的執行緒池完成,如下:
@Configuration @EnableAsync public class AsyncConfiguration { @Bean("doSomethingExecutor") public Executor doSomethingExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 核心线程数:线程池创建时候初始化的线程数 executor.setCorePoolSize(10); // 最大线程数:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程 executor.setMaxPoolSize(20); // 缓冲队列:用来缓冲执行任务的队列 executor.setQueueCapacity(500); // 允许线程的空闲时间60秒:当超过了核心线程之外的线程在空闲时间到达之后会被销毁 executor.setKeepAliveSeconds(60); // 线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池 executor.setThreadNamePrefix("do-something-"); // 缓冲队列满了之后的拒绝策略:由调用线程处理(一般是主线程) executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy()); executor.initialize(); return executor; } }
使用的方式非常簡單,在需要非同步的方法上加上@Async註解
@RestController public class AsyncController { @Autowired private AsyncService asyncService; @GetMapping("/open/something") public String something() { int count = 10; for (int i = 0; i < count; i++) { asyncService.doSomething("index = " + i); } return "success"; } } @Slf4j @Service public class AsyncService { // 指定使用beanname为doSomethingExecutor的线程池 @Async("doSomethingExecutor") public String doSomething(String message) { log.info("do something, message={}", message); try { Thread.sleep(1000); } catch (InterruptedException e) { log.error("do something error: ", e); } return message; } }
存取:127.0.0.1:8080/open/something,日誌如下
#由此可見已經可見已經可見已經可見達到非同步執行的效果了,並且使用到了咱們配置的線程池。 取得非同步方法傳回值 當非同步方法有回傳值時,如何取得非同步方法執行的回傳結果呢?這時需要非同步呼叫的方法帶有傳回值CompletableFuture。 CompletableFuture是對Feature的增強,Feature只能處理簡單的非同步任務,而CompletableFuture可以將多個非同步任務進行複雜的組合。如下:#2023 -02-06 23:42:42.486 INFO 21168 --- [io-8200-exec-17] x.g.b.system.controller.AsyncController : do something end, time 8 milliseconds##2023838-0283:48 INFO 21168 --- [ do-something-1] x.gits.boot.system.service.AsyncService : do something, message=index = 0
2023-02-06 23:42:42.488 INFO 2118 --- [ do-something-5] x.gits.boot.system.service.AsyncService : do something, message=index = 4
2023-02-06 23:42:42.488 INFO 21168 --- [ do-something- 4] x.gits.boot.system.service.AsyncService : do something, message=index = 3
2023-02-06 23:42:42.488 INFO 21168 --- [ do-something-6] x.gits .boot.system.service.AsyncService : do something, message=index = 5
2023-02-06 23:42:42.488 INFO 21168 --- [ do-something-9] x.gits.boot.system. service.AsyncService : do something, message=index = 8
2023-02-06 23:42:42.488 INFO 21168 --- [ do-something-8] x.gits.boot.Service.service.Asydo system.service.Asydonc 系統. something, message=index = 7
2023-02-06 23:42:42.488 INFO 21168 --- [do-something-10] x.gits.boot.system.service.AsyncService : do something, message=index.AsyncService : do something, message=index = 9
2023-02-06 23:42:42.488 INFO 21168 --- [ do-something-7] x.gits.boot.system.service.AsyncService : do something, message=index = 6
2023-02-06 23:42:42.488 INFO 21168 --- [ do-something-2] x.gits.boot.system.service.AsyncService : do something, message=index = 1
#2023-02-06 23:42:42.488 INFO 21168 --- [ do-something-3] x.gits.boot.system.service.AsyncService : do something, message=index = 2
@RestController public class AsyncController { @Autowired private AsyncService asyncService; @SneakyThrows @ApiOperation("异步 有返回值") @GetMapping("/open/somethings") public String somethings() { CompletableFuture<String> createOrder = asyncService.doSomething1("create order"); CompletableFuture<String> reduceAccount = asyncService.doSomething2("reduce account"); CompletableFuture<String> saveLog = asyncService.doSomething3("save log"); // 等待所有任务都执行完 CompletableFuture.allOf(createOrder, reduceAccount, saveLog).join(); // 获取每个任务的返回结果 String result = createOrder.get() + reduceAccount.get() + saveLog.get(); return result; } } @Slf4j @Service public class AsyncService { @Async("doSomethingExecutor") public CompletableFuture<String> doSomething1(String message) throws InterruptedException { log.info("do something1: {}", message); Thread.sleep(1000); return CompletableFuture.completedFuture("do something1: " + message); } @Async("doSomethingExecutor") public CompletableFuture<String> doSomething2(String message) throws InterruptedException { log.info("do something2: {}", message); Thread.sleep(1000); return CompletableFuture.completedFuture("; do something2: " + message); } @Async("doSomethingExecutor") public CompletableFuture<String> doSomething3(String message) throws InterruptedException { log.info("do something3: {}", message); Thread.sleep(1000); return CompletableFuture.completedFuture("; do something3: " + message); } }
C:\Users\Administrator>curl -X GET "http://localhost:8080/open/something" -H "accept: * /*"控制台上關鍵日誌如下:do something1: create order;
do something2: reduce account;
do something3: save log
2023-02-06 00:27:42.238 INFO 5672 --- [ do-something-3] x.gits.boot.system.service.AsyncService : do something3: save log注意事項 @Async註解會在以下幾個場景失效,也就是說明明使用了@Async註解,但就沒有走多執行緒。#2023-02- 06 00:27:42.238 INFO 5672 --- [ do-something-2] x.gits.boot.system.service.AsyncService : do something2: reduce account
2023-02-06 00:27:402. --- [ do-something-1] x.gits.boot.system.service.AsyncService : do something1: create order
2023-02-06 00:27: reduce account
2023-02-06 00:27: reduce account
##在同一個類別中,一個方法調用另外一個有@Async註解的方法,註解不會生效。原因是@Async註解的方法,是在代理類別中執行的。
要注意的是: 非同步方法使用註解@Async的回傳值只能為void或Future及其子類,當傳回結果為其他類型時,方法還是會非同步執行,但是傳回值都是null,部分原始碼如下:
##AsyncExecutionInterceptor#invoke 透過上邊幾個範例,@Async實際上還是透過Future或CompletableFuture來非同步執行的,Spring又封裝了一下,讓我們使用的更方便。以上是在SpringBoot怎麼優雅的使用多線程的詳細內容。更多資訊請關注PHP中文網其他相關文章!