阅读量:0
1、需求
配置中,固定周期,单位秒。需要任务每间隔这个秒数 执行进行统计。
2、分析
要实现这个需求,之前一直在用的多线程方案也行。详见
既然前面用quartz 根据cron表达式上一次和下一次的执行时间判断。
本次就用quartz来实现动态任务。
毫无疑问,quartz更专业,功能更强大。支持事务,支持任务持久化。事务这边不需要。持久化看产品需求了。
3、编码实现
3.1 QuartzSchedulerConfig
@Configuration public class QuartzSchedulerConfig { @Bean public SchedulerFactoryBean schedulerFactory() { SchedulerFactoryBean factory = new SchedulerFactoryBean(); factory.setBeanName("rules-scheduler"); factory.setOverwriteExistingJobs(true); factory.setAutoStartup(true); return factory; } }
3.2 FixedCycleSchedule
动态实现新增和删除 - 与数据库记录匹配
public class FixedCycleSchedule { private static final String GROUP = "fixed"; @Autowired SchedulerFactoryBean schedulerFactoryBean; @Scheduled(fixedRate = 60 * 1000) private void configureTasks() { log.info("fixed cycle schedule single round start"); Scheduler scheduler = schedulerFactoryBean.getScheduler(); Map<String,CustomData> map = DbService.getFixedCycle().stream().collect(Collectors.toMap(CustomData::getId, Function.identity())); try { List<String> existingList = new ArrayList<>(16); for (TriggerKey triggerKey : scheduler.getTriggerKeys(GroupMatcher.groupEquals(GROUP))) { String taskName = triggerKey.getName(); if (!map.containsKey(taskName)) { System.out.println("remove " + taskName); scheduler.unscheduleJob(triggerKey); scheduler.deleteJob(JobKey.jobKey(taskName, GROUP)); continue; } existingList.add(taskName); } List<CustomData> adds = new ArrayList<>(16); for (String s : map.keySet()) { if(!existingList.contains(s)) { adds.add(map.get(s)); } } if(!adds.isEmpty()) { newTasks(scheduler,adds); } } catch (Exception e) { log.error(e.getMessage()); } log.info("fixed cycle schedule single round end"); } private void newTasks(Scheduler scheduler, List<CustomData> adds) throws Exception{ for (CustomData customData : adds) { JobDetail jobDetail = JobBuilder.newJob(MyJob.class) .withIdentity(customData.getId(), GROUP) .build(); SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(customData.getCycle()) .repeatForever(); Trigger trigger = TriggerBuilder.newTrigger() .withIdentity(customData.getId(), GROUP) .startNow() .withSchedule(scheduleBuilder) .build(); System.out.println("newTasks " + customData.getId()); scheduler.scheduleJob(jobDetail, trigger); } } }
用spring的schedule每一分钟同步一次。
3.3 Job
public class MyJob implements Job { @Override public void execute(JobExecutionContext context) throws JobExecutionException { // 获取 Trigger Trigger trigger = context.getTrigger(); TriggerKey key = trigger.getKey(); // 获取 Scheduler Scheduler scheduler = context.getScheduler(); System.out.println("context.getJobDetail().getKey().getName() = " + key.getName()); System.out.println("Job executed at " + new Date()); SimpleTrigger t = (SimpleTrigger)trigger; System.out.println("t.getRepeatInterval() = " + t.getRepeatInterval()); try { if(queryDatabaseForNewSecond == 1) { scheduler.pauseTrigger(key); scheduler.unscheduleJob(key); } } catch (SchedulerException e) { e.printStackTrace(); } } }
queryDatabaseForNewSecond==1 可以用来与库中对比,周期配置如有变更,那么需要更新。一开始打算在job中直接更新,更新也是需要停掉,再newScheduleBuilder、newTrigger,再启 。那么直接停掉。外面的FixedCycleSchedule也会再新建
4、结语
Quartz 方式
优点
高级调度能力:
- Quartz 提供了丰富的调度功能,如固定间隔、固定频率、基于日历的调度等。
- 可以轻松配置复杂的调度策略,如在特定日期和时间执行任务。
任务管理:
- 支持任务的暂停、恢复、取消等功能。
- 可以查看任务的状态,如是否正在执行、何时执行等。
持久化支持:
- Quartz 可以将调度信息持久化到数据库中,这样即使应用程序重启,调度也不会丢失。
- 支持集群部署,可以在多个节点之间共享调度信息。
灵活性:
- 支持多种类型的触发器,如
SimpleTrigger
和CronTrigger
。 - 可以配置多个触发器来调度同一个作业。
- 支持多种类型的触发器,如
健壮性:
- Quartz 在设计时考虑了高可用性和容错性。
- 支持故障转移和恢复,可以在任务失败时自动重试。
多线程方式
优点
简单易用:
- Java 提供了强大的多线程支持,如
Thread
和Runnable
接口。 - 可以轻松创建线程并控制线程的生命周期。
- Java 提供了强大的多线程支持,如
轻量级:
- 相对于 Quartz,多线程模型更为轻量级。
- 不需要额外的配置或持久化支持。
灵活的任务执行:
- 可以根据需要自由控制线程的启动和停止。
- 可以使用
ExecutorService
来管理线程池,提高资源利用率。
择优而用!