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

一。Spring提供了兩種調度任務的方式。

調度任務,@Scheduled
異步任務,@Async

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

1,定時任務單線程執行的時間問題。

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

@Component
public class TestTask {

    @Scheduled(fixedRate = 1000 * 10)   //每10秒執行一次
    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任務每10秒執行一次進入測試");
    }

}

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

}

2)實現SchedulingConfigurer和AsyncConfigurer配置線程池。

@Configuration
@EnableAsync
@EnableScheduling
public class AppConfig {
}

@Configuration//配置定時任務的線程池,支持定時任務并行處理
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注解,添加到方法上,周期性的調用該方法

簡單的周期性的任務simple periodic scheduling

image.png

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

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

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

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

3)fixedRate 方法每fixedRate毫秒,將被調用一次,不管上次是否結束。 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(年,可選)
*:表示匹配該域的任意值
,逗號: 指定觸發
-:范圍觸發
/:步進觸發。
2)eg:
"0 0-5 14 * * ?" 在每天下午2點到下午2:05范圍內,每1分鐘觸發 一次
"0 0/5 14,18 * * ?" 指定小時14,18點,指定步進值5分鐘,在每天下午2點到2:55期間和下午6點到6:55期間的每5分鐘觸發一次。

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

三,配置定時任務的線程池。

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

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