使用ScheduledExecutorService執行緒池手動動態控制定時任務
阿新 • • 發佈:2021-07-28
背景
在日常開發過程中,使用定時任務去執行一些業務邏輯是很常見的一種場景。比如定時傳送簡訊,郵件,電商系統的定時自動收貨、定時上下架功能等等。
一般實現定時任務有以下幾種方案:
JDK自帶
- JDK自帶的Timer:這是java自帶的java.util.Timer類,這個類允許你排程一個java.util.TimerTask任務。使用這種方式可以讓你的程式按照某一個頻度執行,一般用的較少。
- JDK1.5+ 新增的ScheduledExecutorService:是基於執行緒池設計的定時任務類,每個排程任務都會分配到執行緒池中的一個執行緒去執行,也就是說,任務是併發執行,互不影響。
第三方框架
使用 Quartz、elastic-job、xxl-job 等開源第三方定時任務框架,適合分散式專案應用。不過配置起來稍顯複雜,不太易上手。
Spring Task
Spring3.0以後自帶的task,可以將它看成一個輕量級的Quartz,而且使用起來比Quartz簡單許多。使用 Spring 提供的一個註解 @Schedule即可,開發簡單,使用比較方便。
本文主要向大家介紹使用ScheduledExecutorService操作定時任務。
使用
1.啟動類新增@EnableScheduling註解
2.建立定時任務類
ScheduleController.java
/** * <p> * 介面控制定時任務開始和停止 * </p> * * @className ScheduleController *@author Sue * @date 2021/7/28 **/ @RestController @RequestMapping("/task") public class ScheduleController { ScheduleTaskService scheduleTaskService; public ScheduleController(ScheduleTaskService scheduleTaskService) { this.scheduleTaskService = scheduleTaskService; } @PostMapping("/startCron") public R startCron() { scheduleTaskService.startCorn(); return R.ok("定時任務啟動成功!"); } @PostMapping("/stopCron") public R stopCron() { scheduleTaskService.stopCorn(); return R.ok("定時任務關閉成功!"); } }
ScheduleTaskService.java
/** * <p> * 定時任務 * </p> * * @className ThreadPoolTaskSchedulerService * @author Sue * @create 2021/7/21 **/ public interface ScheduleTaskService { /** * <p> * 開始定時任務 * </p> * * @return boolean * @author Sue * @date 2021/7/21 */ boolean startCorn(); /** * <p> * 關閉定時任務 * </p> * * @return boolean * @author Sue * @date 2021/7/21 */ boolean stopCorn(); }
ScheduleTaskServiceImpl.java
/** * <p> * 定時任務 * </p> * * @className ThreadPoolTaskSchedulerServiceImpl * @author Sue * @create 2021/7/21 **/ @Slf4j @Service public class ScheduleTaskServiceImpl implements ScheduleTaskService { private ScheduledFuture<?> future; ThreadPoolTaskScheduler threadPoolTaskScheduler; public ScheduleTaskServiceImpl(ThreadPoolTaskScheduler threadPoolTaskScheduler) { this.threadPoolTaskScheduler = threadPoolTaskScheduler; } @Override public boolean startCorn() { if (future != null) { future.cancel(true); log.info("定時任務已停止"); } //每10秒執行一次 String cornConfig = "0/10 * * * * *"; future = threadPoolTaskScheduler.schedule(new ScheduledTaskRunnable(), new CronTrigger(cornConfig)); log.info("定時任務開啟"); return false; } @Override public boolean stopCorn() { if (future != null) { future.cancel(true); log.info("定時任務已停止"); } return false; } static class ScheduledTaskRunnable implements Runnable { @Override public void run() { //需要執行的業務邏輯 log.info("定時任務開始執行,每10秒執行一次,當前時間{}", LocalDateTimeUtil.format(LocalDateTimeUtil.now(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))); } } }
3.專案啟動後,呼叫介面,控制定時任務的啟動和停止
測試
呼叫startCorn介面,可以看出定時任務成功開啟
呼叫stopCorn介面,停止定時任務
補充
corn表示式的使用
cron 表示式是一個字串,該字串由 6 個空格分為 7 個域,每一個域代表一個時間含義。 通常定義 “年” 的部分可以省略,實際常用的 Cron 表示式由前 6 部分組成。格式如下:
[秒] [分] [時] [日] [月] [周] [年]
Seconds Minutes Hours Day-of-Month Month Day-of-Week Year (optional field)
需要說明的是,Cron 表示式中,“周” 是從週日開始計算的。“周” 域上的 1 表示的是週日,7 表示週六。
萬用字元說明
- * 表示所有值. 例如:在分的欄位上設定 “*”,表示每一分鐘都會觸發
- ? 表示不指定值。使用的場景為不需要關心當前設定這個欄位的值。例如:要在每月的10號觸發一個操作,但不關心是周幾,所以需要周位置的那個欄位設定為"?" 具體設定為 0 0 0 10 * ?
- - 表示區間。例如 在小時上設定 “10-12”,表示 10,11,12點都會觸發。
- , 表示指定多個值,例如在周欄位上設定 “MON,WED,FRI” 表示週一,週三和週五觸發
- / 用於遞增觸發。如在秒上面設定"5/15" 表示從5秒開始,每增15秒觸發(5,20,35,50)。 在月欄位上設定’1/3’所示每月1號開始,每隔三天觸發一次。
- L 表示最後的意思。在日欄位設定上,表示當月的最後一天(依據當前月份,如果是二月還會依據是否是潤年[leap]), 在周欄位上表示星期六,相當於"7"或"SAT"。如果在"L"前加上數字,則表示該資料的最後一個。例如在周欄位上設定"6L"這樣的格式,則表示“本月最後一個星期五"
- W 表示離指定日期的最近那個工作日(週一至週五). 例如在日欄位上設定"15W",表示離每月15號最近的那個工作日觸發。如果15號正好是週六,則找最近的週五(14號)觸發, 如果15號是周未,則找最近的下週一(16號)觸發.如果15號正好在工作日(週一至週五),則就在該天觸發。如果指定格式為 “1W”,它則表示每月1號往後最近的工作日觸發。如果1號正是週六,則將在3號下週一觸發。(注,“W"前只能設定具體的數字,不允許區間”-").
- # 序號(表示每月的第幾個周幾),例如在周欄位上設定"6#3"表示在每月的第三個週六.注意如果指定"#5",正好第五週沒有周六,則不會觸發該配置(用在母親節和父親節再合適不過了) ;
提示:
'L’和 'W’可以組合使用。如果在日欄位上設定"LW",則表示在本月的最後一個工作日觸發;
周欄位的設定,若使用英文字母是不區分大小寫的,即MON 與mon相同;
例子
- "0 */1 * * * ?" 每隔 1 分鐘執行一次
- "0 24,30 * * * ?" 在24分,30分執行一次
- "0 0 10,14,16 * * ?" 每天上午10點,下午2點,4點
- "0 0/30 9-17 * * ?" 朝九晚五工作時間內每半小時
- "0 0 12 ? * WED" 表示每個星期三中午12點
- "0 0 12 * * ?" 每天中午12點觸發
- "0 15 10 ? * *" 每天上午10:15觸發
- "0 15 10 * * ?" 每天上午10:15觸發
- "0 15 10 * * ? *" 每天上午10:15觸發
- "0 15 10 * * ? 2005" 2005年的每天上午10:15觸發
- "0 * 14 * * ?" 在每天下午2點到下午2:59期間的每1分鐘觸發
- "0 0/5 14 * * ?" 在每天下午2點到下午2:55期間的每5分鐘觸發
- "0 0/5 14,18 * * ?" 在每天下午2點到2:55期間和下午6點到6:55期間的每5分鐘觸發
- "0 0-5 14 * * ?" 在每天下午2點到下午2:05期間的每1分鐘觸發
- "0 10,44 14 ? 3 WED" 每年三月的星期三的下午2:10和2:44觸發
- "0 15 10 ? * MON-FRI" 週一至週五的上午10:15觸發
- "0 15 10 15 * ?" 每月15日上午10:15觸發
- "0 15 10 L * ?" 每月最後一日的上午10:15觸發
- "0 15 10 ? * 6L" 每月的最後一個星期五上午10:15觸發
- "0 15 10 ? * 6L 2002-2005" 2002年至2005年的每月的最後一個星期五上午10:15觸發
- "0 15 10 ? * 6#3" 每月的第三個星期五上午10:15觸發