spring自帶的定時任務功能@EnableScheduling


1 demo

package  com.test.domi.config;
 
import  org.springframework.beans.factory.annotation.Configurable;
import  org.springframework.scheduling.annotation.EnableScheduling;
import  org.springframework.scheduling.annotation.Scheduled;
import  org.springframework.stereotype.Component;
import  java.text.SimpleDateFormat;
import  java.util.Date;
 
@Component
@Configurable
@EnableScheduling
public  class  ScheduledTasks {
     //每30秒執行一次
     @Scheduled (fixedRate =  1000  30 )
     public  void  reportCurrentTime(){
         System.out.println ( "Scheduling Tasks Examples: The time is now "  + dateFormat ().format ( new  Date ()));
     }
 
     //在固定時間執行
     @Scheduled (cron =  "0 */1 *  * * * " )
     public  void  reportCurrentByCron(){
         System.out.println ( "Scheduling Tasks Examples By Cron: The time is now "  + dateFormat ().format ( new  Date()));
     }
 
     private  SimpleDateFormat dateFormat(){
         return  new  SimpleDateFormat ( "HH:mm:ss" );
     }
Scheduling Tasks Examples: The time is now 11:55:54
Scheduling Tasks Examples By Cron: The time is now 11:56:00
Scheduling Tasks Examples: The time is now 11:56:24
Scheduling Tasks Examples: The time is now 11:56:54
Scheduling Tasks Examples By Cron: The time is now 11:57:00

 

2 詳解

http://tramp.cincout.cn/2017/08/18/spring-task-2017-08-18-spring-boot-enablescheduling-analysis/

cron表達式:https://www.zhyd.me/article/43

1.cron是設置定時執行的表達式,如 0 0/5 * * * ?每隔五分鍾執行一次

2.zone表示執行時間的時區

3.fixedDelay 和fixedDelayString 一個固定延遲時間執行,上個任務完成后,延遲多久執行

4.fixedRate 和fixedRateString一個固定頻率執行,上個任務開始后多長時間后開始執行

5.initialDelay 和initialDelayString表示一個初始延遲時間,第一次被調用前延遲的時間

 

3 總結常見問題

a: 單線程任務丟失,轉為異步線程池

默認的 ConcurrentTaskScheduler 計划執行器采用Executors.newSingleThreadScheduledExecutor() 實現單線程的執行器。因此,對同一個調度任務的執行總是同一個線程。如果任務的執行時間超過該任務的下一次執行時間,則會出現任務丟失,跳過該段時間的任務。上述問題有以下解決辦法:

采用異步的方式執行調度任務,配置 Spring 的 @EnableAsync,在執行定時任務的方法上標注 @Async配置任務執行池,線程池大小 n 的數量為 單個任務執行所需時間 / 任務執行的間隔時間。如下:


//每30秒執行一次
    @Async ( "taskExecutor" )
    @Scheduled (fixedRate =  1000  3 )
    public  void  reportCurrentTime(){
        System.out.println ( "線程"  + Thread.currentThread().getName() +  "開始執行定時任務===&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&7&&&====》"
                new  SimpleDateFormat( "yyyy-MM-dd HH:mm:ss" ).format( new  Date()));
        long  start = System.currentTimeMillis();
        Future<Boolean> isOk1;
        Future<Boolean> isOk2;
   。 。。。。。。。。。省略。。。。。。。
 

b: 關於分布式情況下,重復執行的問題(兩種方案)

1:可以使用redis的分布式鎖保證spring schedule集群只執行一次。 redis分布式鎖是通過setnx命令實現的。該命令的作用是,當往redis中存入一個值時,會先判斷該值對應的key是否存在,如果存在則返回0,如果不存在,則將該值存入redis並返回1。(但是在分布式跨時區部署的時候,依然無法避免重復執行)

@Component
@Configuration
@EnableScheduling
public  class  AutoConvertTask {
     private  static  final  Logger logger = LoggerFactory.getLogger(AutoConvertTask. class );
 
     @Autowired
     private  RedisTemplate redisTemplate;
 
     private  static  final  String LOCK =  "task-job-lock" ;
 
     private  static  final  String KEY =  "tasklock" ;
 
     @Scheduled (cron =  "0 0 0 * * ? " )
     public  void  autoConvertJob() {
         boolean  lock =  false ;
         try  {
             lock = redisTemplate.opsForValue().setIfAbsent(KEY, LOCK);
             logger.info( "是否獲取到鎖:"  + lock);
             if  (lock) {
                 List<GameHistory> historyList = historyService.findTenDaysAgoUntreated();
                 for  (GameHistory history : historyList) {
                     update(history);
                 }
             else  {
                 logger.info( "沒有獲取到鎖,不執行任務!" );
                 return ;
             }
         finally  {
             if  (lock) {
                 redisTemplate.delete(KEY);
                 logger.info( "任務結束,釋放鎖!" );
             else  {
                 logger.info( "沒有獲取到鎖,無需釋放鎖!" );
             }
         }
 
     }
 
}

 

2:可以通過使用shedlock將spring schedule上鎖。詳細見:https://segmentfault.com/a/1190000011975027

 

c: 服務器宕機之后,丟失的任務如何補償? 

可以將每次的任務執行時間緩在redis里,下次執行任務的時候都取出該時間,判斷是否為上一個周期,如果不是,可以計算出中間丟失的周期數,然后做響應的補償操作。如果怕redis宕機,可以將“執行時間”持久化到表中。


免責聲明!

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



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