定时任务
简介:
日常生活中有多定时任务的应用场景,比如闹钟每天指定时间叫你起床,比如监控系统,隔断时间采集数据,对异常报警。
TimerTask和Timer:
TimerTask表示的时一个定时任务类,它是一个抽象类,实现了runnable接口,具体的定时任务类需要继承该类,实现run方法。
Timer:具体执行类,负责定时任务的调度和执行。Timer内部是有一任务队列和Timer线程组成。任务队列是一个基于堆实现的优先级队列,按照下次执行时间排优先级。因为只有一个线程,所有有时候任务会被延迟处理,且Timer线程主体是一个循环,循环处理任务队列中的任务。
Timer常用的方法:
方法名 | 返回值 | 说明 |
---|---|---|
schedule(TimerTask task,Date time) | void | 在绝对时间点执行任务 |
schedule(TimerTask task,long delay) | void | 在当前时间延时delay毫秒后运行 |
schedule(TimerTask task,Date firstTime,long period) | void | 固定延时重复执行,第一次执行时间时firstTime, 后面执行时间是上一次实际执行时间+period |
schedule(TimerTask task,long delay,long period) | 固定延时重复执行, 当前时间+delay为第一次执行之间,后面的都是实际执行时间加period | |
scheduleAtFixedRate(TimerTask,Date firstTime,long period) | void | 固定频率执行,第一次执行时间是firstTime,后面执行时间都是前一次实际执行时间+period |
scheduleAtFixedRate(TimerTask,long delay,long period) | void | 固定频率执行,第一次执行时间是当前时间+delay,后面每一次执行都是前一次实际执行时间+period |
public class TimedTask {
static class MyTimerTask extends TimerTask {
@Override
public void run() {
System.out.println("定时任务1");
try {
Thread.sleep(2000);
}catch (InterruptedException i){
i.printStackTrace();
}
System.out.println("执行完毕");
}
}
static class MineTimerTask extends TimerTask {
@Override
public void run() {
System.out.println("定时任务2");
}
}
static class LockTimerTask extends TimerTask {
@Override
public void run() {
while(true){
System.out.println("定时任务会有死循环");
}
}
}
static class ExceptionTimerTask extends TimerTask {
@Override
public void run() {
System.out.println("发生异常后所有定时任务都会被取消");
throw new RuntimeException();
}
}
public static void main(String[] args) throws Exception {
Timer timer = new Timer();
MyTimerTask myTimerTask = new MyTimerTask();
MineTimerTask mineTimerTask = new MineTimerTask();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//指定绝对时间执行任务
timer.schedule(myTimerTask,simpleDateFormat.parse("2021-3-17 10:33:00"));
//当前时间加指定延时毫秒时间执行任务
timer.schedule(myTimerTask,1000);
//指定第一次执行时间按固定的延时时间重复执行
timer.schedule(myTimerTask,simpleDateFormat.parse("2021-3-17 10:40:00"),1000);
//当前时间+延时毫秒时间按固定延时时间重复执行
timer.schedule(myTimerTask,1000,1000);
//指定第一次执行时间,按固定频率指定的延时时间执行任务
timer.schedule(myTimerTask,simpleDateFormat.parse("2021-3-17 10:42:00"),1000);
//当前时间+延时时间按固定频率重复执行
timer.schedule(myTimerTask,1000,1000);
//timer内部主要是由任务队列和Timer线程两部分组成。任务队列是一个基于堆实现的优先级队列
//按照下次执行的时间排优先级。Timer线程负责执行所有的定时任务,需要强调的是,一个Timer
//对象只有一个Timer线程,所以下面的例子,任务二会延时处理。Timer线程主体是个循环,
timer.schedule(myTimerTask,1000);
timer.schedule(mineTimerTask,1000);
//下面任务2会一下子处理多次任务,因为延时相对的是任务执行前的当前时间,所以固定频率会补足之前等待的时间的频率次数
timer.schedule(myTimerTask,10);
timer.scheduleAtFixedRate(mineTimerTask,100,1000);
//因为Timer只有一个线程,所以当有一个人发生死循环时,后面的任务就永远无法执行了
timer.schedule(myTimerTask,100,1000);
LockTimerTask lockTimerTask = new LockTimerTask();
timer.schedule(lockTimerTask,100,1000);
//当有一个任务发生异常,后面的所有任务都会被取消,所以一定要在任务重写的run方法内捕获异常
timer.schedule(myTimerTask,100,1000);
ExceptionTimerTask exceptionTimerTask = new ExceptionTimerTask();
timer.schedule(exceptionTimerTask,100,1000);
}
}
TimerTask 和Timer 的注意点:
(1)Timer调度类内部只有一个线程。内部的队列是基于堆实现的优先级队列。会按照下次执行时间排优先级,但是由于只有一个线程,有时任务会被延迟执行。
(2)固定频率的任务被延迟后,可能会立即执行多次,将次数补够。
(3)固定延时任务的延时相对的时任务执行前的时间,也就是说当上一个任务休眠或者其他原因时,后一个任务会被延时相应的时间。
(4)不可以在任务内部无限循环,会导致后面任务无法执行。
(5)一个定时任务未处理异常就会导致所有任务都被取消。
ScheduledExecutorService:
并发包下的定时任务接口ScheduleExecutorService实现了执行服务接口ExecutorService:它的实现类是scheduledThreadPoolExecutor集成了ThreadPoolExecutor。所以没有了固定频率一下子执行多条的情况第一执行时间是initialDelay后,后面都是加period。而固定延时任务的延时时间也更为合理了,是任务执行之后的时间+period。
同时当一个任务出现异常时也不会影响其他任务,只是发生这个异常的任务被终止。它的任务队列是一个无界的优先级队列,所以做大线程数对它没有作用,即使corePoolSize为0,它也至少有一个线程在运行。
ScheduledThreadPoolExecutor 常用方法:
//单次执行Runnable任务,执行时间是当前时间+delay
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) {
if (command != null && unit != null) {
RunnableScheduledFuture<Void> t = this.decorateTask((Runnable)command, new ScheduledThreadPoolExecutor.ScheduledFutureTask(command, (Object)null, this.triggerTime(delay, unit), sequencer.getAndIncrement()));
this.delayedExecute(t);
return t;
} else {
throw new NullPointerException();
}
}
//单次执行Callable任务,执行时间是当前时间+delay
public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) {
if (callable != null && unit != null) {
RunnableScheduledFuture<V> t = this.decorateTask((Callable)callable, new ScheduledThreadPoolExecutor.ScheduledFutureTask(callable, this.triggerTime(delay, unit), sequencer.getAndIncrement()));
this.delayedExecute(t);
return t;
} else {
throw new NullPointerException();
}
}
//固定频率执行任务,第一次执行时间是当前时间+initialDelay,后面每次执行时间是执行任务结束后时间+period
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) {
if (command != null && unit != null) {
if (period <= 0L) {
throw new IllegalArgumentException();
} else {
ScheduledThreadPoolExecutor.ScheduledFutureTask<Void> sft = new ScheduledThreadPoolExecutor.ScheduledFutureTask(command, (Object)null, this.triggerTime(initialDelay, unit), unit.toNanos(period), sequencer.getAndIncrement());
RunnableScheduledFuture<Void> t = this.decorateTask((Runnable)command, sft);
sft.outerTask = t;
this.delayedExecute(t);
return t;
}
} else {
throw new NullPointerException();
}
}
//固定重复执行任务,第一次执行时间是当前时间+initialDelay,后面每次执行时间是执行任务结束后时间+period
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) {
if (command != null && unit != null) {
if (delay <= 0L) {
throw new IllegalArgumentException();
} else {
ScheduledThreadPoolExecutor.ScheduledFutureTask<Void> sft = new ScheduledThreadPoolExecutor.ScheduledFutureTask(command, (Object)null, this.triggerTime(initialDelay, unit), -unit.toNanos(delay), sequencer.getAndIncrement());
RunnableScheduledFuture<Void> t = this.decorateTask((Runnable)command, sft);
sft.outerTask = t;
this.delayedExecute(t);
return t;
}
} else {
throw new NullPointerException();
}
}
Executors工厂类提供的方法:
//单线程的定时任务
public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
return new Executors.DelegatedScheduledExecutorService(new ScheduledThreadPoolExecutor(1));
}
//单线程的定时任务线程,由自定义线程工厂创建线程
public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
return new Executors.DelegatedScheduledExecutorService(new ScheduledThreadPoolExecutor(1, threadFactory));
}
//多线程的定时任务线程,由用户指定线程数
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
//多线程的定时任务线程,由用户指定线程数,由自定义的线程工厂创建线程
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory) {
return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}
public class ScheduleExecutorServiceMine {
static class OrderTimerTask implements Runnable {
@Override
public void run() {
System.out.println("并发定时任务A");
try {
Thread.sleep(2000);
}catch (InterruptedException i){
i.printStackTrace();
}
}
}
static class SortTimerTak implements Callable<Integer> {
@Override
public Integer call() throws Exception {
System.out.println("定时任务B");
return 1;
}
}
static class ExceptionConcurrentTimerTask implements Runnable {
@Override
public void run() {
System.out.println("异常任务");
throw new RuntimeException();
}
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
ScheduledExecutorService scheduleExecutorService =
(ScheduledExecutorService) new ScheduledThreadPoolExecutor(2);
OrderTimerTask orderTimerTask = new OrderTimerTask();
SortTimerTak sortTimerTak = new SortTimerTak();
//当前时间单次延时执行
scheduleExecutorService.schedule(orderTimerTask,1000, TimeUnit.MILLISECONDS);
//返回的ScheduledFuture扩展了异步结果接口Future<V>和Delayed接口
ScheduledFuture<Integer> future = scheduleExecutorService.schedule(sortTimerTak,1000,TimeUnit.MILLISECONDS);
System.out.println(future.get());
ScheduledExecutorService scheduledExecutorService1 = Executors.newScheduledThreadPool(10);
ExceptionConcurrentTimerTask exceptionTimer = new ExceptionConcurrentTimerTask();
scheduledExecutorService1.scheduleAtFixedRate(exceptionTimer,1000,1000,TimeUnit.MILLISECONDS);
}
}
总结:
我们本章节学习了定时任务的基本使用和内部基础原理,TimerTask和Timer并发