一文教你实现Spring动态启停定时任务

为什么需要定时任务定时任务的应用场景十分广泛 , 如定时清理文件、定时生成报表、定时数据同步备份等 。
JAVA定时任务的原理【一文教你实现Spring动态启停定时任务】jdk自带的库中 , 有两种技术可以实现定时任务 , 一种是Timer,另一种是
ScheduledThreadPoolExecutor
Timer+TimerTask

Timer是一个线程 , 控制执行TimerTask所需要执行的内容
public class Timer {/*** The timer task queue.This data structure is shared with the timer* thread.The timer produces tasks, via its various schedule calls,* and the timer thread consumes, executing timer tasks as Appropriate,* and removing them from the queue when they're obsolete.*/private final TaskQueue queue = new TaskQueue();/*** The timer thread.*/private final TimerThread thread = new TimerThread(queue);。。。。。。}其中 , 需要注意 , Timer类有几个方法创建不同的线程执行:
延时执行//其中的delay是延时时间 , 表示多少毫秒后执行一次taskpublic void schedule(TimerTask task, long delay) {if (delay < 0)throw new IllegalArgumentException("Negative delay.");sched(task, System.currentTimeMillis()+delay, 0);}指定时间点执行//到达指定时间time的时候执行一次taskpublic void schedule(TimerTask task, Date time) {sched(task, time.getTime(), 0);}延时周期执行//经过delay毫秒后按每period毫秒执行一次的周期执行taskpublic void schedule(TimerTask task, long delay, long period) {if (delay < 0)throw new IllegalArgumentException("Negative delay.");if (period <= 0)throw new IllegalArgumentException("Non-positive period.");sched(task, System.currentTimeMillis()+delay, -period);}指定时间点后周期执行//到达指定时间firstTime之后按照每period毫秒执行一次的周期执行taskpublic void schedule(TimerTask task, Date firstTime, long period) {if (period <= 0)throw new IllegalArgumentException("Non-positive period.");sched(task, firstTime.getTime(), -period);}TimerTask是一个实现了Runable接口的类 , 所以能够放到线程去执行:
public abstract class TimerTask implements Runnable {/*** This object is used to control access to the TimerTask internals.*/final Object lock = new Object();。。。。。。}示例:
public class JavaTimerJob {public static void main(String[] args) {Timer timer = new Timer();Task task = new Task();//当前时间开始 , 每1秒执行一次timer.schedule(task, new Date(),1000);} }class Task extends TimerTask {@Overridepublic void run() {System.out.println(new Date()+":This is my job...");}}执行结果:
Tue May 30 13:45:47 CST 2022:This is my job...Tue May 30 13:45:48 CST 2022:This is my job...Tue May 30 13:45:49 CST 2022:This is my job...Tue May 30 13:45:50 CST 2022:This is my job... 。。。。弊端:Timer是单线程的 , 一旦定时任务中某一过程时刻抛出异常 , 将会导致整体线程停止 , 定时任务停止 。
ScheduledThreadPoolExecutor继承了ThreadPoolExecutor,,是一个基于线程池的调度器 通过实现ScheduledExecutorService接口方法去实现任务调度 , 主要方法如下:
延时执行//command是待执行的线程 , delay表示延时时长 , unit代表时间单位public ScheduledFuture<?> schedule(Runnable command,long delay,TimeUnit unit) {if (command == null || unit == null)throw new NullPointerException();RunnableScheduledFuture<?> t = decorateTask(command,new ScheduledFutureTask<Void>(command, null,triggerTime(delay, unit)));delayedExecute(t);return t;}延时周期执行//command是待执行的线程 , initialDelay表示延时时长 , period代表执行间隔时长 , unit代表时间单位public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit) {if (command == null || unit == null)throw new NullPointerException();if (period <= 0)throw new IllegalArgumentException();ScheduledFutureTask<Void> sft =new ScheduledFutureTask<Void>(command,null,triggerTime(initialDelay, unit),unit.toNanos(period));RunnableScheduledFuture<Void> t = decorateTask(command, sft);sft.outerTask = t;delayedExecute(t);return t;}每段延时间隔执行//command是待执行的线程 , initialDelay表示延时时长 , delay代表每次执行线程前的延时时长 , unit代表时间单位public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit) {if (command == null || unit == null)throw new NullPointerException();if (delay <= 0)throw new IllegalArgumentException();ScheduledFutureTask<Void> sft =new ScheduledFutureTask<Void>(command,null,triggerTime(initialDelay, unit),unit.toNanos(-delay));RunnableScheduledFuture<Void> t = decorateTask(command, sft);sft.outerTask = t;delayedExecute(t);return t;}


推荐阅读