普通的線程池執行流程,應該很多人都知道了,可是定時任務線程更爲重要,很多框架都用到了,應用場景有很多,比如心跳,拉取信息,redisson鎖的續約,同步數據等
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
//shutdown後是否繼續執行定時任務
private volatile boolean continueExistingPeriodicTasksAfterShutdown;
//shutdown後是否繼續執行延遲任務
private volatile boolean executeExistingDelayedTasksAfterShutdown = true;
//cancle方法收費需要將該任務從隊列移除
private volatile boolean removeOnCancel = false;
//任務的序列號
private static final AtomicLong sequencer = new AtomicLong();
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;
}
ScheduledFutureTask
public void run() {
//判斷任務是否週期執行
boolean periodic = isPeriodic();
//檢查當前狀態能否執行任務
if (!canRunInCurrentRunState(periodic))
cancel(false);
//非週期任務直接執行,只執行一次
else if (!periodic)
ScheduledFutureTask.super.run();
//週期任務的執行
else if (ScheduledFutureTask.super.runAndReset()) {
//設置下一次執行任務時間
setNextRunTime();
//任務的下一次執行
reExecutePeriodic(outerTask);
}
}
//沒做什麼事情,留給後面的擴展點
protected <V> RunnableScheduledFuture<V> decorateTask(
Runnable runnable, RunnableScheduledFuture<V> task) {
return task;
}
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();
}
}
DelayedWorkQueue,阻塞獲取頭結點
public RunnableScheduledFuture<?> take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
for (;;) {
RunnableScheduledFuture<?> first = queue[0];
if (first == null)
available.await();
else {
long delay = first.getDelay(NANOSECONDS);
if (delay <= 0)
return finishPoll(first);
first = null; // don't retain ref while waiting
if (leader != null)
//已經存在leader線程,當前線程await阻塞
available.await();
else {
//當前線程作爲leader線程,並制定頭結點的延遲時間作爲阻塞時間
Thread thisThread = Thread.currentThread();
leader = thisThread;
try {
available.awaitNanos(delay);
} finally {
if (leader == thisThread)
leader = null;
}
}
}
}
} finally {
//leader線程沒有阻塞,可以找到頭結點,喚醒阻塞線程
if (leader == null && queue[0] != null)
available.signal();
lock.unlock();
}
}
//根據前面設置的時間,跟當前時間比較,計算要等待的時間
public long getDelay(TimeUnit unit) {
return unit.convert(time - now(), NANOSECONDS);
}
//進行按時間排序,形成一個小頂堆
private void siftUp(int k, RunnableScheduledFuture<?> key) {
while (k > 0) {
int parent = (k - 1) >>> 1;
RunnableScheduledFuture<?> e = queue[parent];
if (key.compareTo(e) >= 0)
break;
queue[k] = e;
setIndex(e, k);
k = parent;
}
queue[k] = key;
setIndex(key, k);
}