Spring中@Async註解使用及配置
Spring中@Async
註解使用及配置
參考文章:https://blog.csdn.net/weixin_42272869/article/details/123082657
一、@Async
註解的使用
在使用spring框架中,可以非常簡單方便的實現一個非同步執行方法,具體只需要在啟動類新增@EnableAsync
註解開啟支援非同步,然後在需要進行非同步處理的方法上使用@Async
註解即可進行非同步執行。
注意:想要非同步執行,不能在一個類中直接呼叫本類中被@Async
註解標記的方法,本類中直接呼叫會同步執行,不會進行非同步執行
主啟動類
@EnableAsync//開啟非同步支援,也可以標記在被@Configuration註解標註的類上,效果一致 @SpringBootApplication public class ApplicationTest{ .... }
使用例項:需要交給spring容器管理bean
@Component
public class MyAsyncService {
@Async//直接使用非同步註解即可,預設使用的執行緒池就是自定義實現的執行緒池
public void testAsync(){
System.out.println("==== 我執行了 ====");
System.out.println("MyAsyncService.testAsync() = " + Thread.currentThread().getName());
}
}
測試執行:
/* 使用SpringBoot執行測試 */ @SpringBootTest(classes = ApplicationTest.class) public class ApplicationTest1 { @Resource MyAsyncService myAsyncService; @Test void testTread(){ myAsyncService.testAsync(); System.out.println("結束.... " ); } }
測試結果:
二、@Async
註解執行緒池的配置及使用
1、@Async預設執行緒池修改
對於修改@Async使用的預設執行緒池,我們可以使用實現AsyncConfigurer
介面,並重寫getAsyncExecutor()方法,為其提供我們自己定義的執行緒池即可
具體示例:
import lombok.extern.slf4j.Slf4j; import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; 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.lang.reflect.Method; import java.util.concurrent.Executor; import java.util.concurrent.ThreadPoolExecutor; /** * 描述:執行緒池配置類,修改@Async註解預設使用的執行緒池 * * @author SXT * @version 1.0 * @date 2022/11/22 */ //開啟自動啟用非同步註解,與配置類放在一起,方便管理 @EnableAsync @Configuration @Slf4j public class AsyncTaskPoolConfig implements AsyncConfigurer { /** * 用於@Async註解獲取預設執行緒連線池 * @return */ @Override public Executor getAsyncExecutor() { //此類由Spring提供,org.springframework.scheduling.concurrent包下,是執行緒池的封裝類 ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); //執行緒池中執行緒的名字字首 taskExecutor.setThreadNamePrefix("taskThreadPool-async-"); //執行緒池核心執行緒數量 taskExecutor.setCorePoolSize(5); //執行緒池最大執行緒數量 taskExecutor.setMaxPoolSize(10); //執行緒池空閒執行緒存活時間,單位秒 taskExecutor.setKeepAliveSeconds(100); //執行緒池拒絕策略 taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy()); //執行緒池任務隊容量,如果不設定則預設 Integer.MAX_VALUE, // 佇列預設使用LinkedBlockingQueue 若queueCapacity的值 <= 0,則使用SynchronousQueue taskExecutor.setQueueCapacity(1000); //執行緒池中核心執行緒是否允許超時,預設為false taskExecutor.setAllowCoreThreadTimeOut(true); //執行緒池中的超時處理時間,單位秒,有一個對應方法為毫秒,預設為不超時 taskExecutor.setAwaitTerminationSeconds(60); //初始化執行緒池,不可以少,否者會丟擲 執行緒池沒有初始化 taskExecutor.initialize(); return taskExecutor; } /** * 執行緒未處理異常的統一處理機制,即執行緒池異常處理器,簡單示例 * @return */ @Override public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { // 異常處理器函式介面類 return new AsyncUncaughtExceptionHandler() { @Override public void handleUncaughtException(Throwable throwable, Method method, Object... objects) { log.error("============ " + throwable.getMessage() + " ===========", throwable); log.error("============ " + method.getName() + " ===========", objects); } }; } }
實現AsyncConfigurer
類中的getAsyncExecutor()方法後,在使用@Async註解進行非同步執行時,預設使用的執行緒池就是實現提供的執行緒池,具體使用示例如下:
/**
* 描述:非同步方法呼叫
*
* @author SXT
* @version 1.0
* @date 2022/11/23
*/
@Component
public class MyAsyncService {
@Async//直接使用非同步註解即可,預設使用的執行緒池就是自定義實現的執行緒池
public void testAsync(){
System.out.println("==== 我執行了 ====");
System.out.println("MyAsyncService.testAsync() = " + Thread.currentThread().getName());
}
}
/* 使用SpringBoot執行測試 */
@SpringBootTest(classes = ApplicationTest.class)
public class ApplicationTest1 {
@Resource
MyAsyncService myAsyncService;
@Test
void testTread(){
myAsyncService.testAsync();
System.out.println("結束.... " );
}
}
測試執行結果如下:如實使用實現提供的執行緒池
2、自定義執行緒池(@Async指定使用自定義執行緒池)
無論是修改@Async預設提供的執行緒池還是不修改,都可以對某些使用@Async標註的非同步執行方法為其指定使用具體的某一個執行緒池,若想要使用指定的執行緒池需要明確的為@Async註解指定使用的執行緒池名稱(自定義的執行緒池需要交給Spring管理),也就是bean的名稱
自定義執行緒池示例:可以看到與修改@Async預設執行緒池中提供執行緒池的內容一樣,執行緒池具體的配置可以根據需求進行設定
@Configuration
public class CommentConfig {
/**
* 自定義非同步執行緒池,bean的名字如果不顯示的指定,則預設使用方法的名稱作為bean的名稱
* @return
*/
@Bean("asyncTaskPool")
public Executor asyncTaskPool(){
//此類由Spring提供,org.springframework.scheduling.concurrent包下,是執行緒池的封裝類
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//執行緒池中執行緒的名字字首
executor.setThreadNamePrefix("asyncTaskPool-task-");
//執行緒池核心執行緒數量
executor.setCorePoolSize(5);
//執行緒池最大執行緒數量
executor.setMaxPoolSize(10);
//執行緒池空閒執行緒存活時間,單位秒
executor.setKeepAliveSeconds(100);
//執行緒池拒絕策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//執行緒池任務隊容量,如果不設定則預設 Integer.MAX_VALUE,
// 佇列預設使用LinkedBlockingQueue 若queueCapacity的值 <= 0,則使用SynchronousQueue
executor.setQueueCapacity(1000);
//執行緒池中核心執行緒是否允許超時,預設為false
executor.setAllowCoreThreadTimeOut(true);
//執行緒池中的超時處理時間,單位秒,有一個對應方法為毫秒,預設為不超時
executor.setAwaitTerminationSeconds(60);
//初始化執行緒池,不可以少,否者會丟擲 執行緒池沒有初始化
executor.initialize();
return executor;
}
}
使用自定義執行緒池示例:
/**
* 描述:非同步方法呼叫
*
* @author SXT
* @version 1.0
* @date 2022/11/23
*/
@Component
public class MyAsyncService {
//指定使用執行緒池的bean的名稱,不指定的話使用的是預設提供的執行緒池
//asyncTaskPool就是被Spring管理的執行緒池例項的物件名稱
@Async("asyncTaskPool")
public void testAsync2(){
System.out.println("==== 我執行了 ====");
System.out.println("MyAsyncService.testAsync2() = " + Thread.currentThread().getName());
}
}
/* 使用SpringBoot執行測試 */
@SpringBootTest(classes = ApplicationTest.class)
public class ApplicationTest1 {
@Resource
MyAsyncService myAsyncService;
@Test
void testTread2(){
myAsyncService.testAsync2();
System.out.println("結束.... " );
}
}
測試結果如下:
拓展:
若想要根據配置檔案進行動態的配置自定義執行緒池,則可以使用如下方式
配置檔案properties檔案或yml檔案
#這裡使用properties檔案進行配置,yml檔案同樣的方式,只是格式不同
#也可以將駝峰命名改成core-size ,keep-alive-seconds,對應的實體類依舊是駝峰命名
asyncTask.pool.coreSize=5
asyncTask.pool.maxPoolSize=10
asyncTask.pool.keepAliveSeconds=60
asyncTask.pool.queueCapacity=1000
asyncTask.pool.timeOutSeconds=60
定義獲取配置檔案對應配置的類
/**
* 描述:執行緒池配置檔案實體類
*
* @author SXT
* @version 1.0
* @date 2022/11/23
*/
//使用@ConfigurationProperties註解,其類必須交給Spring管理
@ConfigurationProperties(prefix = "async-task.pool")
@Component
@ToString
@Data
public class ThreadConfig {
private int coreSize;
private int maxPoolSize;
private long keepAliveSeconds;
private int queueCapacity;
private long timeOutSeconds;
}
@SpringBootTest(classes = ApplicationTest.class)
public class ApplicationTest1 {
@Autowired
ThreadConfig threadConfig;
@Test
void testProperties1(){
System.out.println("threadConfig = " + threadConfig);
}
}
測試結果:
提示:配置的key不要寫錯,不然獲取不到值
三、@Async
註解的原理
待完善