一、创建简单调度任务
根据官方文档,我们基于Bean(类)模式创建一个调度任务
public class MyJobHandler1 extends IJobHandler {
@Override
public ReturnT<String> execute(String param) throws Exception {
System.out.println(new Date() + " MyJobHandler1启动");
return null;
}
}
在启动类中注册进去
@SpringBootApplication
public class XxlJobExecutorApplication {
public static void main(String[] args) {
SpringApplication.run(XxlJobExecutorApplication.class, args);
XxlJobExecutor.registJobHandler("myJobHandler1", new MyJobHandler1());
}
}
随后在调度中心页面配置服务
准备就绪,启动服务。可以看到成功打印出日志。
在配置服务的时候,有个重要参数:阻塞处理策略,参考官方文档,有3种处理策略
- 单机串行(默认):调度请求进入单机执行器后,调度请求进入FIFO队列并以串行方式运行;
- 丢弃后续调度:调度请求进入单机执行器后,发现执行器存在运行的调度任务,本次请求将会被丢弃并标记为失败;
- 覆盖之前调度:调度请求进入单机执行器后,发现执行器存在运行的调度任务,将会终止运行中的调度任务并清空队列,然后运行本地调度任务;
下面就测试阻塞模式下的运行结果
二、阻塞模式测试
如果被调度的任务还没有运行结束,此时调度中心将该任务停止,然后修改了参数和运行时间,再点击运行,这样被调度任务会怎样?先修改一下之前的代码
public class MyJobHandler1 extends IJobHandler {
@Override
public ReturnT<String> execute(String param) throws Exception {
System.out.println(new Date() + " 线程" + Thread.currentThread().getId() + " 开始运行,参数:" + param);
Thread.sleep(1000 * 60);
System.out.println(new Date() + " 线程" + Thread.currentThread().getId() + " 运行结束,参数:" + param);
return null;
}
}
首先,在代码里强制sleep60秒,然后先让任务在每分钟0秒执行,执行未结束时,停止任务,修改参数,再在每分钟30秒执行。
2.1、单机串行模式
运行结果如图
可以发现,修改参数后,还是同一个线程,并且不是每分钟30秒才执行,而是等上一个任务执行完才会执行下一个。因此正如官方文档中所说的,到达调度设置的时间点后,是将调度命令放入队列中,依次执行。所以这会造成几个问题:
1、任务除了第一次运行的时间是和调度设置的时间一样外,其余的都可能不一样
2、调度中心停止任务后,被调度的任务也不会再执行完后立即停止,而是要等队列中所有调度命令全部执行完。比如调度中心设置每分钟执行一次,但该任务执行一次要半小时。那么过了10分钟后,即使停止任务,那么该任务依旧会运行10次。
2.2、丢弃后续调度
运行结果如图
可以发现,修改参数后,如果任务已经在运行了,就直接放弃本次任务
2.3、覆盖之前调度
运行结果如图
可以发现,修改参数后,如果已经有任务在运行了,会被强制终止,然后创建新的线程执行本次任务
综上,在实际场景中,阻塞策略不建议选择单机串行。