什么是定时任务调度
定时任务调度:基于给定的时间点,给定的时间间隔或者给定的执行次数自动执行任务。
两种java定时任务调度工具却别
Timer | Quartz |
---|---|
小弟!功能简单,开销小 | 大哥!强大完善 |
jdk1.5 | 需要引入jar包 |
一个后台线程 | 后台执行线程池 |
Timer
有且仅有一个后台线程,对多个业务线程进行定时定频率的调度
主要构件:
Timer类中两个成员变量:
- TimerThread后台线程
- TaskQueue成员TimerTask[]
TimerThread的run方法来回调用TimerTask的run方法
总之,Timer—定时调用 TimerTask
使用
编写MyTimerTask类继承TimerTask类并重写run()方法,然后用Timer调用schedule方法来执行任务
import java.util.TimerTask;
public class MyTimerTask extends TimerTask{
private String name;
public MyTimerTask(String name){
this,name = name;
}
@Override
public void run(){
System.out.println("This thread is " + this,name);
}
//set get
}
Timer类
public class MyTimer{
public static void main(String[] args){
Timer timer = new Timer();
MyTimerTask myTimerTask = new MyTimerTask ("name1");
//通过timer定时调用myTimerTask的run
//2秒之后执行,此后每3秒执行一次
timer.schedule(myTimerTask,2000L,3000L);
}
}
schedule其他用法:
1.timer.schedule(task,time);//time距1970年的毫秒数,只执行一次
2.timer.schedule(task,time,period);//time首次执行任务时间,每隔period毫秒再执行
3.timer.schedule(task,delay); //等待delay毫秒后,执行且仅执行一次task
4.timer.schedule(task,delay,period); //等待delay毫秒后,每隔period毫秒再执行scheduleAtFixedRate的两种用法(暂时理解为同上)(有一定的并发能力) 1.timer.scheduleAtFixedRate(task,time,period);//和上面第二种方法一样
2.timer.scheduleAtFixedRate(task,delay,period);//和上面第四种方法一样
其他重要函数
TimerTask的两个函数
- cancel() 取消当前TimerTask里的任务[在类里执行]
- scheduledExecutionTime(),返回最近发生此任务的时间 毫秒[在主方法里执行
myTimerTask.scheduledExecutionTime()
]
import java.util.TimerTask;
public class MyTimerTask extends TimerTask{
private String name;
private int count = 0;
public MyTimerTask(String name){
this,name = name;
}
@Override
public void run(){
System.out.println("This thread is " + this,name);
count++;
if(count==3){
//□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
cancel();//取消当前任务运行!!!!!!!!!!!!!!!!
//□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
}
}
//set get
}
Timer的两个函数
- cancel() 中止所有安排的任务
- purge() 移除队列中已取消的任务,返回溢出的任务数
总结
天生缺陷 1: 不支持并发,是同步执行的,串行执行
天生缺陷 2: Timer中执行的任务,如果有异常抛出,timer就会终止,后续的任务不会再执行,推荐使用ScheduledExecutorService。
阿里推荐的编码规约中这样写道
多线程并行处理定时任务时,Timer运行多个TimeTask时
,只要其中之一没有捕获抛出的异常,其它任务便会自动终止运行
,使用ScheduledExecutorService则没有这个问题。
//org.apache.commons.lang3.concurrent.BasicThreadFactory
ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1,
new BasicThreadFactory.Builder()
.namingPattern("example-schedule-pool-%d").daemon(true).build());
executorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
//do something
}
},initialDelay,period, TimeUnit.HOURS);
springboot整合定时任务task只支持单点
@EnableScheduling
在配置类上使用,开启计划任务的支持(类上)@Scheduled
来申明这是一个任务,包括cron,fixDelay,fixRate等类型(方法上,需先开启计划任务的支持)``
//主要启动类
@SpringBootApplication()
@EnableScheduling
@MapperScan("com.***.dao")
public class managerToolApplication {
public static void main(String[] args) {
ProcessUtil.setProcessID();
ApplicationContext app = SpringApplication.run(managerToolApplication.class, args);
SpringUtil.setApplicationContext(app);
SpringUtil.scannerBeans();
}
}
//定时计划类
@Component
public class AlarmTask {
/**
** @Scheduled(fixedRate = 2000)第一种:每两秒执行一次
* @Scheduled(cron = "0 0/10 * * * ?")第二种 :cron表达式
*/
@Scheduled(cron = "0 0/1 * * * ?")
public void computerMonitor() {
//具体逻辑
}
/*
fixedRate 说明
@Scheduled(fixedRate = 6000) :上一次开始执行时间点之后6秒再执行
@Scheduled(fixedDelay = 6000) :上一次执行完毕时间点之后6秒再执行
@Scheduled(initialDelay=1000, fixedRate=6000) :第一次延迟1秒后执行,之后按 fixedRate 的规则每6秒执行一次
*/
}
springboot不支持年
六位 0 0/10 * ?
秒 分 时 日 月 年
4-40 4到40秒打印
0/10 从0开始,每10秒一执行
在线自动生成cron
支持分布式(整合redis,做分布式锁)
/**
* Redis锁(防止多点定时任务执行重复)
*
* @author zhaojianyu
* @date 2019/7/5
*/
public class RedisLockUtils {
/**
* 锁定资源 value
*/
private static final String REDIS_LOCK_VALUE = "rtqerq342r1f341f";
/**
* 锁状态 true:已上锁
*/
private static boolean status = false;
/**
* 上锁
*
* @param redisTemplate
* @param time 超时时间(防止死锁)
* @param timeUnit 时间单位
*/
public static void lock(RedisTemplate<String, Object> redisTemplate, int time, TimeUnit timeUnit, String key) {
if (!status) {
redisTemplate.opsForValue().set(key, REDIS_LOCK_VALUE, time, timeUnit);
status = true;
}
}
/**
* 获取锁
*
* @param redisTemplate
*/
public static boolean getLock(RedisTemplate<String, Object> redisTemplate, String key) {
status = redisTemplate.opsForValue().get(key) != null;
return status;
}
/**
* 强制拆锁
*
* @param redisTemplate
* @param key
*/
public static void delLock(RedisTemplate<String, Object> redisTemplate, String key) {
redisTemplate.delete(key);
status = false;
}
/**
* 获取锁剩余生存时间
*
* @param redisTemplate
* @param key
* @return
*/
public static long getLockTime(RedisTemplate<String, Object> redisTemplate, String key) {
return redisTemplate.getExpire(key);
}
/**
* 随机等待
*/
public static void randomWait() {
try {
Random ra = new Random();
TimeUnit.SECONDS.sleep(ra.nextInt(4));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}