第一步:啓用定時任務
第二步:配置定時器資源等
第三步:定義定時任務並指定觸發規則web
在springboot入口類上添加註解@EnableScheduling便可。spring
@SpringBootApplication(scanBasePackages = {}) @MapperScan("com.dx.jobmonitor.mapper") @EnableScheduling public class App { private static final Logger logger = LoggerFactory.getLogger(App.class); public static void main(String[] args) { logger.info("App start..."); SpringApplication.run(App.class, args); } }
設置定時任務線程池大小:經過SchedulingConfigurer接口配置並行方式
當定時任務不少的時候,爲了提升任務執行效率,能夠採用並行方式執行定時任務,任務之間互不影響,只要實現SchedulingConfigurer接口就能夠。 數據庫
/** * 配置定時任務<br> * 1)當定時任務不少的時候,爲了提升任務執行效率,能夠採用並行方式執行定時任務,任務之間互不影響,只要實現SchedulingConfigurer接口就能夠。<br> * 2)這裏指定用3個線程來並行處理 * **/ @Configuration public class ScheduledConfig implements SchedulingConfigurer { @Override public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) { scheduledTaskRegistrar.setScheduler(setTaskExecutors()); } @Bean(destroyMethod = "shutdown") public Executor setTaskExecutors() { return Executors.newScheduledThreadPool(3); } }
在並行執行的時候,建立線程池採用了newScheduledThreadPool這個線程池。
Executors框架中存在幾種線程池的建立線程池的採用的隊列是延遲隊列:express
newScheduledThreadPool() 線程池的特性是定時任務可以定時或者週期性的執行任務。springboot
public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue()); }
其中線程池核心線程數是本身設定的,最大線程數是最大值。阻塞隊列是自定義的延遲隊列:DelayedWorkQueue()app
定時任務1:框架
@Component public class SchedulerTask { private int count=0; @Scheduled(cron="*/6 * * * * ?") private void process(){ System.out.println("this is scheduler task runing "+(count++)); } }
定時任務2:ide
從application.yml中讀取cron參數函數
@Component public class Scheduler2Task { private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss"); @Scheduled("jobs.scheduled.cron") public void reportCurrentTime() { System.out.println("如今時間:" + dateFormat.format(new Date())); } }
此時application.yml中配置信息以下:測試
jobs:
scheduled:
cron: 0/30 * * * * ?
參數說明:
@Scheduled接受兩種定時的設置:
- 一種是cornexpression。
- 一種是Rate/Delay表達式(毫秒值):
- @Scheduled(fixedRate = 6000):上一次開始執行時間點後每隔6秒執行一次。
- @Scheduled(fixedDelay = 6000):上一次執行完畢時間點以後6秒再執行。
- @Scheduled(initialDelay=1000, fixedRate=6000):第一次延遲1秒後執行,以後按fixedRate的規則每6秒執行一次。
動態修改定時任務cron參數時:
@Component public class SpringDynamicCronTask implements SchedulingConfigurer { private static final Logger logger = LoggerFactory.getLogger(SpringDynamicCronTask.class); private static String cron = "0/5 * * * * ?"; @Autowired private TaskDynamicCronService taskCronService; @Override public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) { scheduledTaskRegistrar.addTriggerTask(() -> { // 任務邏輯 logger.error("dynamicCronTask is running..."); }, triggerContext -> { // 任務觸發,在這裏可修改任務的執行週期,由於每次調度都會執行這裏 // 1)這裏能夠修改成從數據讀取cron // cron=taskCronService.getCron(); CronTrigger cronTrigger = new CronTrigger(cron); return cronTrigger.nextExecutionTime(triggerContext); }); } /** * 2) 供應用端調用動態修改cron參數方法 * @Controller * @RequestMapping("/cron")") * public class CronController{ * @Autowired * private SpringDynamicCronTask cronTask; * * @PostMapping("/update") * @ResponseBody * public String update(String cron) { * cronTask.setCron(cron); * } * } */ public void setCron(String cron) { this.cron=cron; } }
動態設置cron參數經常使用方式包含兩種:
定義CronTrigger時,從數據庫中動態查詢cron並設置
@Autowired private TaskDynamicCronService taskCronService; @Override public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) { scheduledTaskRegistrar.addTriggerTask(() -> { // 任務邏輯 logger.error("dynamicCronTask is running..."); }, triggerContext -> { cron=taskCronService.getCron(); CronTrigger cronTrigger = new CronTrigger(cron); return cronTrigger.nextExecutionTime(triggerContext); }); }
SpringDynamicCronTask 類,提供修改cron函數setCron()。
@Component public class SpringDynamicCronTask implements SchedulingConfigurer { private static final Logger logger = LoggerFactory.getLogger(SpringDynamicCronTask.class); private static String cron = "0/5 * * * * ?"; @Override public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) { scheduledTaskRegistrar.addTriggerTask(() -> { // 任務邏輯 logger.error("dynamicCronTask is running..."); }, triggerContext -> { CronTrigger cronTrigger = new CronTrigger(cron); return cronTrigger.nextExecutionTime(triggerContext); }); } /** * 供應用端調用動態修改cron參數方法 */ public void setCron(String cron) { this.cron=cron; } }
應用端調用:
@Controller @RequestMapping("/cron")") public class CronController{ @Autowired private SpringDynamicCronTask cronTask; @PostMapping("/update") @ResponseBody public String update(String cron) { cronTask.setCron(cron); } }
定義多定時任務管理類
class BatchTaskSchedule { private ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler(); private ScheduledFuture<?> future; private Integer key; public BatchTaskSchedule(Integer key) { this.key = key; } public void start() { executor.setPoolSize(1); executor.setThreadNamePrefix("taskExecutor-"); executor.setWaitForTasksToCompleteOnShutdown(true); executor.setAwaitTerminationSeconds(60); // 必須得先初始化,才能使用 executor.initialize(); future = executor.schedule(new Runnable() { @Override public void run() { System.out.println("[" + Thread.currentThread().getName() + "-" + key + "]Hello " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); } }, new CronTrigger("0/15 * * * * ?")); } public void restart() { // 先中止,在開啓. stop(); start(); } public void stop() { if (future != null) { future.cancel(true); } } }
使用測試示例:
@RunWith(SpringJUnit4ClassRunner.class) @SpringBootTest(classes = { App.class }, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) public class CommonTest { // 定時任務存儲集合:當須要中止、重啓任務時,能夠從該集合中獲取待操做任務。 private static Map<Integer, BatchTaskSchedule> taskBack = new HashMap<Integer, BatchTaskSchedule>(); @Test public void test() { for (int i = 0; i < 2; i++) { // 建立定時任務 BatchTaskSchedule taskScheduled = new BatchTaskSchedule(i); taskScheduled.start(); taskBack.put(i, taskScheduled); } try { Thread.sleep(1 * 60 * 1000); // 中止掉某個任務 taskBack.get(0).stop(); Thread.sleep(1 * 60 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } } }