我們在使用多線程的時候,往往需要創建Thread類,或者實現Runnable接口,如果要使用到線程池,我們還需要來創建Executors,在使用spring中,已經給我們做了很好的支持。只要要@EnableAsync就可以使用多線程。使用@Async就可以定義一個線程任務。通過spring給我們提供的ThreadPoolTaskExecutor就可以使用線程池。
默認情況下,Spring將搜索相關的線程池定義:要么在上下文中搜索唯一的TaskExecutor bean,要么搜索名為“taskExecutor”的Executor bean。如果兩者都無法解析,則將使用SimpleAsyncTaskExecutor來處理異步方法調用。
定義配置類
@Configuration
@EnableAsync
public class ThreadPoolTaskConfig {
private static final int corePoolSize = 10; // 核心線程數(默認線程數)
private static final int maxPoolSize = 100; // 最大線程數
private static final int keepAliveTime = 10; // 允許線程空閑時間(單位:默認為秒)
private static final int queueCapacity = 200; // 緩沖隊列數
private static final String threadNamePrefix = "Async-Service-"; // 線程池名前綴
@Bean("taskExecutor") // bean的名稱,默認為首字母小寫的方法名
public ThreadPoolTaskExecutor getAsyncExecutor(){
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
executor.setKeepAliveSeconds(keepAliveTime);
executor.setThreadNamePrefix(threadNamePrefix);
// 線程池對拒絕任務的處理策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 初始化
executor.initialize();
return executor;
}
}
@Configuration用於定義配置類,被注解的類內部包含有一個或多個被@Bean注解的方法,這些方法將會被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext類進行掃描,並用於構建bean定義,初始化Spring容器。
@EnableAsync開始對異步任務的支持
測試service
@Service
public class testAsyncService {
Logger log = LoggerFactory.getLogger(testAsyncService.class);
// 發送提醒短信 1
@Async("taskExecutor")
public void service1() throws InterruptedException {
log.info("--------start-service1------------");
Thread.sleep(5000); // 模擬耗時
log.info("--------end-service1------------");
}
// 發送提醒短信 2
@Async("taskExecutor")
public void service2() throws InterruptedException {
log.info("--------start-service2------------");
Thread.sleep(2000); // 模擬耗時
log.info("--------end-service2------------");
}
}
@Async注解來聲明一個或多個異步任務,可以加在方法或者類上,加在類上表示這整個類都是使用這個自定義線程池進行操作
接着我們可以創建control類@Autowired這個service並且調用這其中兩個方法,進行連續調用,會發現運行結果是
--------start-service1------------
--------start-service2------------
--------end-service2------------
--------end-service1------------
可以說明我們的異步運行成功了
如下方式會使@Async失效
一、異步方法使用static修飾
二、異步類沒有使用@Component注解(或其他注解)導致spring無法掃描到異步類
三、異步方法不能與異步方法在同一個類中
四、類中需要使用@Autowired或@Resource等注解自動注入,不能自己手動new對象
五、如果使用SpringBoot框架必須在啟動類中增加@EnableAsync注解
六、在Async 方法上標注@Transactional是沒用的。 在Async 方法調用的方法上標注@Transactional 有效。
七、調用被@Async標記的方法的調用者不能和被調用的方法在同一類中不然不會起作用!!!!!!!
八、使用@Async時要求是不能有返回值的不然會報錯的 因為異步要求是不關心結果的
下面關於線程池的配置還有一種方式,就是直接實現AsyncConfigurer接口,重寫getAsyncExecutor方法即可,代碼如下
@Configuration
@EnableAsync
public class AppConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(7);
executor.setMaxPoolSize(42);
executor.setQueueCapacity(11);
executor.setThreadNamePrefix("MyExecutor-");
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new MyAsyncUncaughtExceptionHandler();
}
}