一 介紹
工作中經常涉及異步任務,通常是使用多線程技術,比如線程池ThreadPoolExecutor,但使用Executors容易產生OOM,需要手動使用ThreadPoolExecutor創建線程池;在springboot使用 @async 可以實現異步調用,配置線程池參數,可以簡單的實現多線程的線程池效果,從而簡化開發,避免OOM;
二 異步調用
2.1無返回異步
我們知道同步執行就是按照代碼的順序執行,而異步執行則是無序,在springboot中使用實現異步調用函數非常簡單,首先在啟動類上加上@EnableAsync 注解;
/**
* @Author lsc
* <p> </p>
*/
@SpringBootApplication
@EnableAsync
public class AsyncRunApp {
public static void main(String[] args) {
SpringApplication.run(AsyncRunApp.class, args);
}
}
其次,在函數上標上@sync注解,表示異步調用
@Async
public void taskOne() throws Exception {
System.out.println("任務一");
}
@Async
public void taskTwo() throws Exception {
System.out.println("任務二");
}
測試代碼
@Autowired
Task task;
@Test
public void test() throws Exception {
task.taskOne();
task.taskTwo();
}
如果按照同步執行邏輯會先執行任務一,然后再執行任務二,如果是異步執行,則無序,可能任務一先執行,也可能任務二先執行;

2.2 有返回值回調
有時候要知道任務是否執行完成,再繼續做其它的業務邏輯,就需要使用到Future接口,其含義是在執行異步任務后會給一個回調函數,我們只要設置回調信息,就可以知道任務是否正確執行完成;我們對異步函數,添加 Future 返回值類型,使用 new AsyncResult<>() 設置回調信息;
@Component
public class Task {
@Async
public Future<String> taskOne() throws Exception {
System.out.println("任務一");
return new AsyncResult<>("任務一執行完成");
}
@Async
public Future<String> taskTwo() throws Exception {
System.out.println("任務二");
return new AsyncResult<>("任務二執行完成");
}
}
測試代碼如下, 等待2個任務全部完成后就打印出返回值信息
@Autowired
Task task;
@Test
public void test() throws Exception {
Future<String> str1 = task.taskOne();
Future<String> str2 = task.taskTwo();
while (true){
// 如果任務都做完就執行如下邏輯
if (str1.isDone() && str2.isDone()){
System.out.println(str1.get()+":"+str2.get());
break;
}
}
}
執行輸出
任務二
任務一
任務一執行完成:任務二執行完成
關注公眾號 知識追尋者 獲取原創PDF,面試題集,最新成熟技術棧;
三 線程池
在異步掉用中使用的@Async 注解,默認的線程池大小如下;
# 核心線程數
spring.task.execution.pool.core-size=8
# 最大線程數
spring.task.execution.pool.max-size=16
# 空閑線程存活時間
spring.task.execution.pool.keep-alive=60s
# 是否允許核心線程超時
spring.task.execution.pool.allow-core-thread-timeout=true
# 線程隊列數量
spring.task.execution.pool.queue-capacity=100
# 線程關閉等待
spring.task.execution.shutdown.await-termination=false
spring.task.execution.shutdown.await-termination-period=
# 線程名稱前綴
spring.task.execution.thread-name-prefix=task-
一般情況下,我們都需要手動創建線程池,使用 ThreadPoolTaskExecutor 類進行配置;這邊設置了線程前綴名稱,等下測試時就可以判定是否線程池配置成功;
@Configuration
public class PoolConfig {
@Bean
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 設置核心線程數
executor.setCorePoolSize(10);
// 設置最大線程數
executor.setMaxPoolSize(15);
// 設置隊列容量
executor.setQueueCapacity(20);
// 設置線程活躍時間(秒)
executor.setKeepAliveSeconds(60);
// 設置默認線程名稱
executor.setThreadNamePrefix("zszxz-");
// 設置拒絕策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任務結束后再關閉線程池
executor.setWaitForTasksToCompleteOnShutdown(true);
return executor;
}
}
在task類中加上 新的一個方法如下
@Async
public void sayHello(String name) {
LoggerFactory.getLogger(Task.class).info(name + ":Hello World!");
}
使用測試類進行測試
@Test
public void testPool() throws Exception {
task.sayHello("公眾號:知識追尋者");
}
執行結果如下,日志打印出線程名稱為zszxz-1;

有時候,一個項目中如果配置了多個線程池,如下格式
@Bean("pool1")
public TaskExecutor taskExecutor1() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//....
return executor;
}
@Bean("pool2")
public TaskExecutor taskExecutor2() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//....
return executor;
}
@Bean("pool3")
public TaskExecutor taskExecutor3() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//....
return executor;
}
在使用 @Async注解時就需要指明具體使用的線程池,如下格式
@Async("pool1")
public void sayHello1(String name) {
LoggerFactory.getLogger(Task.class).info(name + ":Hello World!");
}
@Async("pool2")
public void sayHello1(String name) {
LoggerFactory.getLogger(Task.class).info(name + ":Hello World!");
}
本套教程
- springboot入門 (1)
- Springboot自定義banner(2)
- springboot配置文件解析(3)
- springboot集成mybatis(4)
- springboot集成jdbcTemplate(5)
- spingboot單元測試(6)
- springboot集成thymeleaf(7)
- springboot多文件上傳(8)
- springboot文件下載(9)
- Springboot自定義異常類(10)
- springboot多環境配置(11)
- springboot自動配置原理解析(12)
- springboot集成restTemplate接口調用(13)
- springboot集成任務調度(14)
- springboot跨域CORS處理(15)
- springboot開啟GIZP壓縮(16)
- springboot集成logback(17)
- springboot集成Swagger(18)
- springboot集成actuator后台監控(19)
- springboot集成mybatis+oracle+druid(20)
- springboot 集成springsession(21)
- springboot集成jwt(22)
- springboot集成admin后台監控(23)
- springboot集成redis基礎篇(24)
- springboot集成redis緩存篇(25)
- springboot使用AOP日志攔截(26)
- springboot集成Validation參數校驗(27)
- springboot集成mybatisPlus(28)
- springboot集成shiro(29)
- springboot實現接口等冪次校驗(30)
- springboot-集成WebSockets(31)
- restTemplate源碼解析(32)
- SpringBoot使用@Async異步調用與線程池(33)
- 待續
- 待續
源碼地址:關注公眾號知識追尋者 回復 springboot
