Spring定時任務(wù)(串行/并行)以及異步任務(wù)

一。Spring提供了兩種調(diào)度任務(wù)的方式。

調(diào)度任務(wù),@Scheduled
異步任務(wù),@Async

1)spring的定時任務(wù)默認是單線程,多個任務(wù)執(zhí)行起來時間會有問題。
2)不論定時任務(wù)被安排在多少個class類中,其依然是單線程執(zhí)行定時任務(wù)(串行任務(wù))。
3)定時任務(wù)并行處理,需手動配置。
4)有多個web容器實例,scheduler會在多個實例上同時運行。
5)shedule流程初始化。
首先spring容器初始化-->通過反射bean初始化之后-->對實例化的bean進行class上的注解掃描-->判斷class中是否有@Scheduled注解-->若有則判斷調(diào)度的模式--> ScheduledAnnotationBeanPostProcessor處理,將掃描到的@Scheduled方法封裝成Runnable,交給線程池(默認單線程)執(zhí)行。
6)定時任務(wù)的方法中,一定不要出現(xiàn)“死循環(huán)”、“http持續(xù)等待無響應(yīng)”現(xiàn)象,否則會導致定時任務(wù)程序無法正常。

1,定時任務(wù)單線程執(zhí)行的時間問題。

1)bTask會因為aTask的sleep(20)而延遲執(zhí)行。

@Component
public class TestTask {

    @Scheduled(fixedRate = 1000 * 10)   //每10秒執(zhí)行一次
    public void aTask(){
        try {
            TimeUnit.SECONDS.sleep(20);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println(sdf.format(DateTime.now().toDate())+"*********A任務(wù)每10秒執(zhí)行一次進入測試");
    }

}

@Component
public class TestTask2 {
    @Scheduled(fixedRate = 5000)   //每5秒執(zhí)行一次
    public void bTask(){
        DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        System.out.println(sdf.format(DateTime.now().toDate())+"*********B任務(wù)每5秒執(zhí)行一次進入測試");
    }

}

2)實現(xiàn)SchedulingConfigurer和AsyncConfigurer配置線程池。

@Configuration
@EnableAsync
@EnableScheduling
public class AppConfig {
}

@Configuration//配置定時任務(wù)的線程池,支持定時任務(wù)并行處理
public class ScheduleConfig implements SchedulingConfigurer {
 
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(taskExecutor());
    }
 
    @Bean(destroyMethod="shutdown")
    public Executor taskExecutor() {
        return Executors.newScheduledThreadPool(100);
    }
}

@Configuration   
public class AsyncConfig 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();  
    }  
} 

二,用法解釋

1,@Scheduled注解,添加到方法上,周期性的調(diào)用該方法

簡單的周期性的任務(wù)simple periodic scheduling

image.png

1)initialDelay: 第一次執(zhí)行方法需要等待時間,單位為毫秒ms。the number of milliseconds to wait before the first execution of the method.
(一般來說,不加該參數(shù),項目重啟,就會立刻執(zhí)行該方法。)

@Scheduled(initialDelay=1000, fixedRate=5000)
public void doSomething() {
    // something that should execute periodically
}

2)fixedDelay: 固定的延遲后再次調(diào)用。當方法第一次被調(diào)用結(jié)束后,延遲固定的ms后,再次調(diào)用。from the completion time of each preceding invocation.從上次調(diào)用的完成時間起。

@Scheduled(fixedDelay=5000)
public void doSomething() {
    // something that should execute periodically
}

3)fixedRate 方法每fixedRate毫秒,將被調(diào)用一次,不管上次是否結(jié)束。 would be executed every fixedRate ms

@Scheduled(fixedRate=5000)
public void doSomething() {
    // something that should execute periodically
}

2,cron表達式。

1)cron表達式, 使用6 - 7 個域
Seconds(秒) Minutes(分) Hours(時) DayOfMonth(第幾日) Month(月) DayOfWeek(星期幾, 1=星期天,2=星期一) Year(年,可選)
*:表示匹配該域的任意值
,逗號: 指定觸發(fā)
-:范圍觸發(fā)
/:步進觸發(fā)。
2)eg:
"0 0-5 14 * * ?" 在每天下午2點到下午2:05范圍內(nèi),每1分鐘觸發(fā) 一次
"0 0/5 14,18 * * ?" 指定小時14,18點,指定步進值5分鐘,在每天下午2點到2:55期間和下午6點到6:55期間的每5分鐘觸發(fā)一次。

@Scheduled(cron="*/5 * * * * MON-FRI")
public void doSomething() {
    // something that should execute on weekdays only
}

三,配置定時任務(wù)的線程池。

1)配置scheduledThreadPool

public class AppConfig implements SchedulingConfigurer{
@Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        logger.info("Configure task registor: {}", taskRegistrar);
        taskRegistrar.setScheduler(taskExecutor());
    }

    @Bean(destroyMethod="shutdown")
    public Executor taskExecutor() {
        return Executors.newScheduledThreadPool(20);
    }
}

2)定時任務(wù)中使用hibernate操作。no hibernate session bound to thread
需要在service層添加@Transactional注解。
@Scheduled 標注的方法最后是包裝到 ScheduledMethodRunnable 中被執(zhí)行的,它是一個 Runnable 接口的實現(xiàn)
沒有添加事務(wù)支持,就不能從線程資源中獲取Session

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,715評論 19 139
  • 博客原文 徒手翻譯spring framework 4.2.3官方文檔的第33章,若有翻譯不當之處請指正。 定時任...
    rabbitGYK閱讀 5,860評論 4 24
  • 不知不覺晃蕩到了十月份,日子過的真的是蠻快的。本來中秋節(jié)就想寫點什么,但是拖延癥,其實也就是懶,控制住了我寫...
    十月十五生閱讀 282評論 0 0
  • 《江城》讀后 在上班路上讀完的《江城》正文,然后一口氣再把后記《回到涪陵》和譯者的《譯后記》讀完,直到最后一...
    MrCold閱讀 315評論 0 0
  • 總在陽臺眺望, 南方西方都是連綿的大山, 雖然北方和東方看不見你, 但我知道,你也在那里。 我睜大眼睛, 想要看清...
    沈小陌閱讀 228評論 0 0

友情鏈接更多精彩內(nèi)容