多線程注解@Async的使用
1.在啟動類Application中添加注解@EnableAsync
2.啟動類需要實現AsyncConfigurer
3.配置線程池
//配置線程池
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
/** 核心線程數(默認線程數) */
taskExecutor.setCorePoolSize(25);
/** 最大線程數 */
taskExecutor.setMaxPoolSize(50);
/** 緩沖隊列大小 */
taskExecutor.setQueueCapacity(25);
/** 允許線程空閑時間(單位:默認為秒) */
taskExecutor.setKeepAliveSeconds(300);
// 線程池對拒絕任務的處理策略
taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
taskExecutor.initialize();
return taskExecutor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return null;
}
實際項目中最大允許的線程數為75個,核心+隊列+max(50-核心)
4.在需要異步的方法中加入@Async,此時需要考慮線程同步問題,可使用CountDownLatch
//對每個數據源開啟一個線程
long start = System.currentTimeMillis();
CountDownLatch countDownLatch = new CountDownLatch(map.size());
for (Integer dbids : map.keySet()) {
List<Integer> integerList = map.get(dbids);
//異步處理
mentService.dealData(countDownLatch, integerList, list);
}
countDownLatch.await();
long end = System.currentTimeMillis();
System.out.println("查詢信息花費:" + (end - start));
@Async
public void dealData(CountDownLatch countDownLatch, List<Integer> integerList,List<Map<String, Object>> list) {
logger.info("當前線程名字" + Thread.currentThread().getName());
try {
} catch (Exception e) {
e.printStackTrace();
} finally {
countDownLatch.countDown();
}
}
CountDownLatch的用法:
CountDownLatch是一個同步工具類,用來協調多個線程之間的同步,構造CountDownLatch的時候需要傳入一個整數n,在這個整數“倒數”到0之前,主線程需要等待在門口,而這個“倒數”過程則是由各個執行線程驅動的,每個線程執行完一個任務“倒數”一次。總結來說,CountDownLatch的作用就是等待其他的線程都執行完任務,必要時可以對各個任務的執行結果進行匯總,然后主線程才繼續往下執行。
@Async注解的注意事項:
1.@SpringBootApplication啟動類當中沒有添加@EnableAsync注解。
2.方法是公有的
3.異步代碼,需要放在外部單獨的類中,不能在同一個類中調用同一個方法,否則會是同步處理
( 據說這是一個“常識”,外部方法才會被Spring攔截器攔截到額),沒有走Spring的代理類。因為@Transactional和@Async注解的實現都是基於Spring的AOP,而AOP的實現是基於動態代理模式實現的。那么注解失效的原因就很明顯了,有可能因為調用方法的是對象本身而不是代理對象,因為沒有經過Spring容器管理。也可以通過自己注入自己的方式)
4.異步方法使用注解@Async的返回值只能為void或者Future
5.debug斷點調試情況下是看不出效果的,可通過在調用后打印時間在異步方法中打印時間的方式查看,如果要debug程序代碼,可以把注解注釋掉
線程的運行說明:
execute(Runable)方法執行過程
如果此時線程池中的數量小於corePoolSize,即使線程池中的線程都處於空閑狀態,也要創建新的線程來處理被添加的任務。
如果此時線程池中的數量等於 corePoolSize,但是緩沖隊列 workQueue未滿,那么任務被放入緩沖隊列。
如果此時線程池中的數量大於corePoolSize,緩沖隊列workQueue滿,並且線程池中的數量小於maxPoolSize,建新的線程來處理被添加的任務。
如果此時線程池中的數量大於corePoolSize,緩沖隊列workQueue滿,並且線程池中的數量等於maxPoolSize,那么通過handler所指定的策略來處理此任務。也就是:處理任務的優先級為:核心線程corePoolSize、任務隊列workQueue、最大線程 maximumPoolSize,如果三者都滿了,使用handler處理被拒絕的任務。
當線程池中的線程數量大於corePoolSize時,如果某線程空閑時間超過keepAliveTime,線程將被終止。這樣,線程池可以動態的調整池中的線程數
具體信息參照https://www.cnblogs.com/redcool/p/6426173.html