SpringBoot(十三):springboot2.0.2定时任务
使用定义任务:
第一步:启用定时任务
第二步:配置定时器资源等
第三步:定义定时任务并指定触发规则
1)启动类启用定时任务
在springboot入口类上添加注解@EnableScheduling即可。
@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); } }
2)配置定时任务资源等:
设置定时任务线程池大小:通过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框架中存在几种线程池的创建线程池的采用的队列是延迟队列:
- newCachedThreadPool() ,
- newFixedThreadPool(),
- newSingleThreadExecutor(),
- newScheduledThreadPool()。
newScheduledThreadPool() 线程池的特性是定时任务能够定时或者周期性的执行任务。
public ScheduledThreadPoolExecutor(int corePoolSize) { super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue()); }
其中线程池核心线程数是自己设定的,最大线程数是最大值。阻塞队列是自定义的延迟队列:DelayedWorkQueue()
3)定义定时任务
定时任务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:
从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秒执行一次。
动态修改scheduled的cron参数:
动态修改定时任务cron参数时:
- 1)不需要重启应用就可以动态的改变Cron表达式的值
- 2)不能使用@Scheduled(cron = “${jobs.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参数常用方式包含两种:
1)动态查询并设置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); }); }
2)通过接口函数修改cron值
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(); } } }
基础才是编程人员应该深入研究的问题,比如:
1)List/Set/Map内部组成原理|区别
2)mysql索引存储结构&如何调优/b-tree特点、计算复杂度及影响复杂度的因素。。。
3)JVM运行组成与原理及调优
4)Java类加载器运行原理
5)Java中GC过程原理|使用的回收算法原理
6)Redis中hash一致性实现及与hash其他区别
7)Java多线程、线程池开发、管理Lock与Synchroined区别
8)Spring IOC/AOP 原理;加载过程的。。。
【+加关注】。