Java定时任务的原理
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是延时时间,表示多少毫秒后执行一次task
public void schedule(TimerTask task, long delay) {
if (delay < 0)
throw new IllegalArgumentException("Negative delay.");
sched(task, System.currentTimeMillis()+delay, 0);
}
指定时间点执行
//到达指定时间time的时候执行一次task
public void schedule(TimerTask task, Date time) {
sched(task, time.getTime(), 0);
}
延时周期执行
//经过delay毫秒后按每period毫秒执行一次的周期执行task
public 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);
}
作者:MrDong先生
链接:https://juejin.cn/post/7111992569034178574
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
指定时间点后周期执行
//到达指定时间firstTime之后按照每period毫秒执行一次的周期执行task
public 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 {
@Override
public void run() {
System.out.println(new Date()+": This is my job...");
}
}
执行结果:
Wed Jul 6 03:45:47 CST 2022: This is my job...
Wed Jul 6 03:45:48 CST 2022: This is my job...
Wed Jul 6 03:45:49 CST 2022: This is my job...
Wed Jul 6 03: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;
}
示例:
public class JavaScheduledThreadPoolExecutor {
public static void main(String[] args) {
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(8);
//延时1秒后开始执行,每3秒执行一次
scheduledExecutorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println(new Date()+": This is my job...");
}
}, 1, 3, TimeUnit.SECONDS);
}
}
执行结果:
Wed Jul 6 03:45:47 CST 2022: This is my job...
Wed Jul 6 03:45:48 CST 2022: This is my job...
Wed Jul 6 03:45:49 CST 2022: This is my job...
Wed Jul 6 03:45:50 CST 2022: This is my job...
。。。。
Timer VS ScheduledThreadPoolExecutor
Timer
- 是单线程,如果开启多个线程服务,将会出现竞争,一旦出现异常,线程停止,定时任务停止;
- 兼容性更高,jdk1.3后使用
ScheduledThreadPoolExecutor
- 基于线程池实现多线程,且自动调整线程数,线程出错并不会影响整体定时任务执行。
- 在jdk1.5后可使用