專案中使用@Scheduled注解(Spring注解)來定時(每隔五分鐘)重繪JVM快取,
但測驗環境和線上環境出現不一樣的效果(如下圖),測驗環境每隔5分鐘重繪一次,而線上環境重繪的時間間隔遠遠超過5分鐘,測驗環境的時間間隔均正常,而線上環境的時間間隔均不正常,
測驗環境:
線上環境:
專案中有若干加載快取的類,加載快取的代碼如下,
@Component public class XXXCache { // 5分鐘 private final long PERIOD = 5L * 60L * 1000L; @Scheduled(fixedRate = PERIOD, initialDelay = PERIOD) public void loadCache() { //TODO } }分析:測驗環境與線上環境代碼一致,但測驗環境加載的快取資料量偏少,
猜測:由于資料量不同,導致測驗環境和線上環境的執行時間間隔出現差異的現象,
進一步猜測:某些類加載快取的時間偏長,導致其他類加載快取的動作長時間處于等待狀態,
?
那么問題來了,被@Scheduled注解的方法是并發執行的呢?還是串行執行的呢?
?
通過斷點除錯,發現在org.springframework.scheduling.config.ScheduledTaskRegistrar#scheduleTasks中,創建了單個執行緒的執行緒池,而這個執行緒池是用來執行整個專案中所有被@Scheduled注解的方法,當某個方法執行時間過久,那么其他方法的任務只能等待,從而導致其他快取的加載時間間隔被拉長,
解決問題的思路:
-
找出加載資料量較多的方法,提高其執行間隔,降低單位時間內的加載次數,
-
修改上述執行緒池的大小,提高并發,
思路1比較好處理,如何處理思路2呢?
?
通過分析代碼org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor#finishRegistration,發現可以使用org.springframework.scheduling.annotation.SchedulingConfigurer來定制org.springframework.scheduling.TaskScheduler
?
見上文截圖中創建單執行緒執行緒池代碼所在的if陳述句,只要我們提前創建TaskScheduler,那么代碼就不會再去創建單執行緒執行緒池的TaskScheduler,在我們自己創建TaskScheduler時,提高執行緒池的大小,從而達到并發的效果,
上代碼:
@Configuration public class ScheduleConfig implements SchedulingConfigurer { @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { //初始化執行緒池 ScheduledThreadPoolExecutor localExecutor = new ScheduledThreadPoolExecutor(3); ConcurrentTaskScheduler taskScheduler = new ConcurrentTaskScheduler(localExecutor); taskRegistrar.setScheduler(taskScheduler); } }看完三件事??
如果你覺得這篇內容對你還蠻有幫助,我想邀請你幫我三個小忙:
-
點贊,轉發,有你們的 『點贊和評論』,才是我創造的動力,
-
關注公眾號 『 java爛豬皮 』,不定期分享原創知識,
-
同時可以期待后續文章ing??
出處:本文來自公眾號:執行緒池
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/226037.html
標籤:Java
上一篇:執行緒池運用不當的一次線上事故
