Spring boot使用多執行緒過程步驟解析
阿新 • • 發佈:2020-08-02
Spring中實現多執行緒,其實非常簡單,只需要在配置類中新增@EnableAsync就可以使用多執行緒。在希望執行的併發方法中使用@Async就可以定義一個執行緒任務。通過spring給我們提供的ThreadPoolTaskExecutor就可以使用執行緒池。
第一步,先在Spring Boot主類中定義一個執行緒池,比如:
package com.jmxf.core.config; import java.util.concurrent.Executor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; @Configuration @EnableAsync // 啟用非同步任務 public class AsyncConfiguration { // 元件計算 @Bean("zjExecutor") public Executor asyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); //核心執行緒數5:執行緒池建立時候初始化的執行緒數 executor.setCorePoolSize(5); //最大執行緒數5:執行緒池最大的執行緒數,只有在緩衝佇列滿了之後才會申請超過核心執行緒數的執行緒 executor.setMaxPoolSize(10); //緩衝佇列500:用來緩衝執行任務的佇列 executor.setQueueCapacity(500); //允許執行緒的空閒時間60秒:當超過了核心執行緒出之外的執行緒在空閒時間到達之後會被銷燬 executor.setKeepAliveSeconds(60); //執行緒池名的字首:設定好了之後可以方便我們定位處理任務所在的執行緒池 executor.setThreadNamePrefix("DailyAsync-"); executor.initialize(); return executor; } }
有很多你可以配置的東西。預設情況下,使用SimpleAsyncTaskExecutor。
第二步,使用執行緒池
在定義了執行緒池之後,我們如何讓非同步呼叫的執行任務使用這個執行緒池中的資源來執行呢?方法非常簡單,我們只需要在@Async註解中指定執行緒池名即可,比如:
package com.jmxf.service.fkqManage.zj; import org.springframework.scheduling.annotation.Async; @Service public class CentreZj { /** * 多執行緒執行 zj計算推數 * @param fkqZj * @throws Exception */ @Async("zjExecutor") public CompletableFuture<String> executeZj (FkqZj fkqZj) { if(fkqZj == null) return; String zjid = fkqZj.getZjid(); FkqHdzjdm zjdm = getZjdm(zjid); String zjlj = zjdm.getZjlj(); if(StringUtils.isBlank(zjlj)) return; Object bean = ApplicationContextProvider.getBean(zjlj); Method method; try { method = bean.getClass().getMethod("refresh",String.class); method.invoke(bean,zjid); } catch (Exception e) { e.printStackTrace(); } } return CompletableFuture.completedFuture(zjid); }
executeZj方法被標記為Spring的 @Async 註解,表示它將在一個單獨的執行緒上執行。該方法的返回型別是 CompleetableFuture 而不是 String,這是任何非同步服務的要求。
第三步,呼叫測試
List<CompletableFuture<String>> executeZjs = new ArrayList<>(); for (FkqZj fkqZj : zjs) { CompletableFuture<String> executeZj = centreZj.executeZj(fkqZj); executeZjs.add(executeZj); } //等待所以子執行緒結束後 返回結果 for (CompletableFuture<String> completableFuture : executeZjs) { CompletableFuture.allOf(completableFuture).join(); }
注意事項
非同步方法和呼叫方法一定要寫在不同的類中,如果寫在一個類中,是沒有效果的!
原因:
spring對@Transactional註解時也有類似問題,spring掃描時具有@Transactional註解方法的類時,是生成一個代理類,由代理類去開啟關閉事務,而在同一個類中,方法呼叫是在類體內執行的,spring無法截獲這個方法呼叫。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。