一、核心总结
01.纯注解 VS 代码
纯注解方式:简单+异步
(同一任务之间也可多线程)
代码方式:可控制定时任务的开启、关闭
,可实时更新cron
表达式,仅不同任务之间的多线程
仍存的问题:task如何同时满足异步、开启关闭、实时更新的方式?
02.核心代码
a.开启关闭
//【创建定时任务线程池】
ThreadPoolTaskScheduler pool = new ThreadPoolTaskScheduler();
pool.initialize(); //使用前需初始化下,默认核心线程为1
//【开启】这个支持cron表达式
ScheduledFuture<?> future = pool.schedule(runnable, new CronTrigger(cron表达式) );
//【关闭】
future.cancel(true);
a.动态读取
将上面的
new CronTrigger(cron表达式)
改为
(executionTime)->{return new CronTrigger(cron表达式).nextExecutionTime(executionTime)
区别:
更改前,在同一个任务中只会调用一次cron字符串;
更改后,在同一任务的每个执行时间截点都会调用一次
故可据此将cron表达式改成一个读取最新cron表达式的方法
例如:
a.调用dao接口从数据库读取cron表达式;
b.从yml中读取,yml修改后结合actuator的@RefreshScope方式主动更新(nacos更好);
c,读取某个excel里的cron表达式
二、纯注解方式
开启定时任务,比放在启动类上
@EnableScheduling
//@EnableAsync //开启异步,保证每次执行都是独立线程
★ 启动类
@Scheduled(cron = "0/5 * * * * ?", //秒 分 时 日 月 周
initialDelay = 2000, //首次任务启动的延迟时间
fixedDelay = 2000, //上次任务end——>下次任务start 的时间间隔
fixedRate = 2000 //两次任务的start时间间隔(毫秒)
)
//@Async //开启多线程
★ 要定时执行的方法
如需调整其他参数,可参考这里
三、代码方式
简易工具类
MyTaskUtil
package org.lm.task;
import cn.hutool.core.date.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @创建信息 : 由 LM 创建于2022/3/19 10:37 (周六)
*/
@RestController
@Slf4j
public class TestController {
@Autowired
private MyTaskUtil myTaskUtil;
/**
* 启动一个定时任务
* @param cron cron表达式
* @param taskName 任务名,为null时会自动取名
* @return
*/
@GetMapping("/start")
public String startInCron(
@RequestParam(required = false,defaultValue = "* * * * * ?") String cron,
@RequestParam(required = false) String taskName
){
return myTaskUtil.startInCron(
() -> {
System.out.println(taskName+" "+Thread.currentThread().getName()+" 记录当前时间:"+ DateUtil.now());
},
cron,
taskName);
}
/**
* 根据任务名去取消定时任务
* @param taskName
*/
@GetMapping("/cancel")
public String cancel(@RequestParam String taskName){
return myTaskUtil.cancel(taskName);
}
/**
* 取消最近添加的任务
*/
@GetMapping("/cancel2")
public String cancelLast(){
return myTaskUtil.cancelLast();
}
/**
* 查询正在运行的任务列表
*/
@GetMapping("/list")
public String findTaskList(){
List<TaskBean> list = myTaskUtil.findTaskList();
String CRLF="\r\n";
StringBuffer sb = new StringBuffer("总数为:"+list.size());
for (TaskBean bean : list) {
sb.append(CRLF).append(bean.toString());
}
System.out.println(sb.toString());
return sb.toString();
}
/**
* 修改定时任务的cron表达式(此处内部通过停止和启动来实现重启的)
* @param cron
* @param taskName
* @return
*/
@GetMapping("/reset")
public String reset(@RequestParam(required = false) String cron, @RequestParam String taskName ){
return myTaskUtil.reset(cron,taskName);
}
/**
* 演示修改定时任务的具体业务
* @param cron
* @param taskName
* @return
*/
@GetMapping("/reset2")
public String reset2(@RequestParam(required = false) String cron, @RequestParam String taskName ){
Runnable runnable=()->{
System.out.println(taskName+" "+DateUtil.now()+"扫描库存为:"+(++count));
};
return myTaskUtil.reset(runnable,cron,taskName);
}
private int count=0; //库存
}