@Scheduled注解的多線程


場景:使用spring框架自帶的定時注解來實現定時任務A,定時任務B

需求:定時任務A的每次任務啟動卡死,不能影響下次定時任務的觸發,更不能影響定時任務B的執行

問題:spring框架自帶的定時,定時任務開啟成功,但所有的任務都是在同一個線程池中的同一個線程來完成的。在實際開發過程中,我們當然不希望所有的任務都運行在一個線程中,此時需要各個定時任務是相互獨立的。

1.定時任務A和定時任務B是相互獨立的,但是定時任務A的某個任務卡死是會影響A的下一個任務出發的,每一個任務都起一條線程去執行,要求必須每個執行完畢后才能再次執行,所以不能開啟異步執行

/**
 * 實現SchedulingConfigurer ,重寫configureTasks 用多線程
 */
@Component
public class SpringCornTask implements SchedulingConfigurer {

    @Autowired
    @Qualifier("updateAsyncExecutor")
    ThreadPoolTaskScheduler threadPoolTaskScheduler;

    //所有加了注解@Scheduled都是用的同一個線程池threadPoolTaskScheduler的線程,同時線程的名字updateAsyncExecutor-
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(threadPoolTaskScheduler);
    }
}
/**
 * 創建定時任務線程池
 */
@Bean("updateAsyncExecutor")
public ThreadPoolTaskScheduler updateAsyncExecutor() {
    ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();
    executor.setPoolSize(3);
    executor.setThreadNamePrefix("updateAsyncExecutor-");
    //用來設置線程池關閉的時候等待所有任務都完成再繼續銷毀其他的Bean
    executor.setWaitForTasksToCompleteOnShutdown(true);
    //該方法用來設置線程池中任務的等待時間,如果超過這個時候還沒有銷毀就強制銷毀,以確保應用最后能夠被關閉,而不是阻塞住。
    executor.setAwaitTerminationSeconds(9000);
    executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());

    return executor;
}
/**
 * 定時任務A
 */
@Scheduled(cron = "0 0 0/4 * * ?")
public void updateRecord() throws IOException {

    log.info("開始執行定時任務===" + new Date() + "===" + Thread.currentThread().getName());
  
    }

2.實現結果是定時任務A和定時任務B是相互獨立的,而且定時任務A的某個任務卡死是不會影響A的下一個任務出發的,同時擔心A和B如果共用同一個線程池,如果任務A卡死,不斷起線程,不斷卡死,會把線程池任務占用完畢,最終會影響到B,更何況A和B的執行頻率差異很大

/**
 * 創建B的線程池
 */
@Bean("cleanAsyncExecutor")
public ThreadPoolTaskScheduler cleanAsyncExecutor() {
    ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();
    executor.setPoolSize(3);
    executor.setThreadNamePrefix("cleanAsyncExecutor-");
    executor.setWaitForTasksToCompleteOnShutdown(true);
    //該方法用來設置線程池中任務的等待時間,如果超過這個時候還沒有銷毀就強制銷毀,以確保應用最后能夠被關閉,而不是阻塞住。
    executor.setAwaitTerminationSeconds(9000);
    executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());

    return executor;
}

    //同理,創建A的線程池
    .................

/**
 * 定時任務A,同時開啟異步,指定線程池updateAsyncExecutor
 */
@Async("updateAsyncExecutor")
@Scheduled(cron = "0 0 0/5 * * ?")
public void updateCompareDataRecord() throws IOException {

    log.info("開始執行定時任務A===" + new Date() + "===" + Thread.currentThread().getName());
    }
/**
 * 定時任務B,同時開啟異步,指定線程池updateAsyncExecutor
 */
@Async("cleanAsyncExecutor")
@Scheduled(cron = "0 0 0 1/1 * ?")
public void cleanDataRecord() throws IOException {
    log.info("開始執行定時任務AB===" + new Date() + "===" + Thread.currentThread().getName());
    }

可以參考:spring scheduled單線程和多線程使用過程中的大坑!!不看到時候絕對后悔!! - hellodev - 博客園 (cnblogs.com)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM