一、schedule
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;
}
public <V> ScheduledFuture<V> schedule(Callable<V> callable,
long delay,
TimeUnit unit) {
if (callable == null || unit == null)
throw new NullPointerException();
RunnableScheduledFuture<V> t = decorateTask(callable,
new ScheduledFutureTask<V>(callable,
triggerTime(delay, unit)));
delayedExecute(t);
return t;
}
- 不同的地方在于一个传入的是Runnable类型,一个传入的是Callable<V>类型,但是Runnable类型最终也会转为Callable类型
- triggerTime是根据delay计算任务的执行时间
private void delayedExecute(RunnableScheduledFuture<?> task) {
// 如果线程池关闭了,拒绝任务
if (isShutdown())
reject(task);
else {
// 将任务加入到队列
super.getQueue().add(task);
// 再判断线程池状态
if (isShutdown() &&
!canRunInCurrentRunState(task.isPeriodic()) &&
remove(task))
task.cancel(false);
// 启动任务
else
ensurePrestart();
}
}
void ensurePrestart() {
// 获取工作线程数
int wc = workerCountOf(ctl.get());
// 启动核心线程
if (wc < corePoolSize)
// 因为这里是定时任务,所以这里firstTask为null
addWorker(null, true);
// 启动非核心线程
else if (wc == 0)
addWorker(null, false);
}
- 根据线程池状态判断是否取消任务
- Worker只是启动线程,最终执行任务还是ScheduledFutureTask#run
public void run() {
// 判断是不是周期性任务,period != 0 就是周期性任务
boolean periodic = isPeriodic();
// 根据线程池状态判断是否需要取消任务
if (!canRunInCurrentRunState(periodic))
cancel(false);
// 如果是不是周期性任务,执行直接
else if (!periodic)
ScheduledFutureTask.super.run();
// 如果是周期性任务,需要重置状态
else if (ScheduledFutureTask.super.runAndReset()) {
// 设置下一次执行的时间
setNextRunTime();
// 重新添加任务
reExecutePeriodic(outerTask);
}
}
二、scheduleAtFixedRate与scheduleWithFixedDelay
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;
}
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;
}
- scheduleAtFixedRate传入的period是正数,scheduleWithFixedDelay传入的period是负数
private void setNextRunTime() {
long p = period;
if (p > 0)
time += p;
else
time = triggerTime(-p);
}
long triggerTime(long delay) {
return now() +
((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay));
}
- 由于scheduleAtFixedRate传入的period为正数,所以下一个任务的执行时间是相对上个任务的开始时间
- 由于scheduleWithFixedDelay传入的period为负数,所以下一个任务的执行时间是相对上个任务的结束时间