什么是定时任务调度
定时任务调度:基于给定的时间点,给定的时间间隔或者给定的执行次数自动执行任务。
两种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;}@Overridepublic 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;}@Overridepublic 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.BasicThreadFactoryScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1,new BasicThreadFactory.Builder().namingPattern("example-schedule-pool-%d").daemon(true).build());executorService.scheduleAtFixedRate(new Runnable() {@Overridepublic 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();}}//定时计划类@Componentpublic 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();}}}
