線程池就是維持幾個(gè)工作線程,然后從任務(wù)隊(duì)列中獲取任務(wù)執(zhí)行。所以要實(shí)現(xiàn)延時(shí)或者定時(shí)執(zhí)行任務(wù),就要做到以下三點(diǎn):
- 任務(wù)要能返回它的延時(shí)時(shí)間和是否為定時(shí)任務(wù)。
- 任務(wù)隊(duì)列要根據(jù)任務(wù)的延時(shí)時(shí)間進(jìn)行排序。這個(gè)我們在上一章DelayedWorkQueue原理分析中已經(jīng)講解過了。
- 如果是定時(shí)任務(wù),任務(wù)執(zhí)行完成之后,還可以再次執(zhí)行它。
所以要分析ScheduledThreadPoolExecutor原理關(guān)鍵就是對它的任務(wù)類ScheduledFutureTask的分析。
private class ScheduledFutureTask<V>
extends FutureTask<V> implements RunnableScheduledFuture<V> {}
FutureTask類我們已經(jīng)在以前的文章分析過了,而RunnableScheduledFuture接口的作用是什么呢?
一. RunnableScheduledFuture接口
我們知道要實(shí)現(xiàn)延時(shí)或者定時(shí)執(zhí)行任務(wù),任務(wù)要能返回它的延時(shí)時(shí)間,任務(wù)是否為定時(shí)任務(wù),任務(wù)能根據(jù)延時(shí)時(shí)間排序。所以可以想象出RunnableScheduledFuture接口中的方法了。
public interface Comparable<T> {
// 比較兩個(gè)實(shí)例的大小
public int compareTo(T o);
}
/**
* 實(shí)現(xiàn)Comparable接口,說明Delayed實(shí)例可以進(jìn)行比較
*/
public interface Delayed extends Comparable<Delayed> {
/**
* @return 返回剩余的延時(shí)時(shí)間
*/
long getDelay(TimeUnit unit);
}
/**
* 實(shí)現(xiàn)了Delayed接口,可以返回延時(shí)時(shí)間以及能夠根據(jù)延時(shí)時(shí)間進(jìn)行比較
*/
public interface ScheduledFuture<V> extends Delayed, Future<V> {
}
// 繼承自Runnable和Future接口??梢援?dāng)做Runnable實(shí)例使用
public interface RunnableFuture<V> extends Runnable, Future<V> {
// 運(yùn)行任務(wù)
void run();
}
public interface RunnableScheduledFuture<V> extends
RunnableFuture<V>, ScheduledFuture<V> {
/**
* 是否為周期定時(shí)任務(wù)
* @return 返回true,表示是定時(shí)任務(wù)
*/
boolean isPeriodic();
}
RunnableScheduledFuture接口中,最重要的就是這四個(gè)方法:
- compareTo(T o): 可以比較任務(wù)的延時(shí)時(shí)間,進(jìn)行排序用的。
- getDelay(TimeUnit unit): 返回任務(wù)剩余的延時(shí)時(shí)間
- run(): 運(yùn)行任務(wù)。如果是定時(shí)任務(wù),任務(wù)完成之后,還可以繼續(xù)執(zhí)行。
- isPeriodic(): 是否為周期定時(shí)任務(wù)
二. 何時(shí)創(chuàng)建ScheduledFutureTask任務(wù)
何時(shí)創(chuàng)建ScheduledFutureTask任務(wù),就是ScheduledExecutorService接口四個(gè)方法會創(chuàng)建ScheduledFutureTask任務(wù)實(shí)例。
2.1 創(chuàng)建延時(shí)任務(wù)
// 給定的延遲時(shí)間delay之后,才會執(zhí)行任務(wù)command
public ScheduledFuture<?> schedule(Runnable command,
long delay,
TimeUnit unit) {
if (command == null || unit == null)
throw new NullPointerException();
/**
* 創(chuàng)建一個(gè)延時(shí)任務(wù)ScheduledFutureTask實(shí)例。
* triggerTime方法會根據(jù)給定的延時(shí)時(shí)間delay,返回任務(wù)開始的時(shí)間。
* decorateTask方法是讓子類能夠修飾ScheduledFutureTask任務(wù)實(shí)例,本類中沒做處理。
*/
RunnableScheduledFuture<?> t = decorateTask(command,
new ScheduledFutureTask<Void>(command, null,
triggerTime(delay, unit)));
// 延時(shí)執(zhí)行任務(wù)
delayedExecute(t);
return t;
}
// 給定的延遲時(shí)間delay之后,才會執(zhí)行任務(wù)callable
public <V> ScheduledFuture<V> schedule(Callable<V> callable,
long delay,
TimeUnit unit) {
if (callable == null || unit == null)
throw new NullPointerException();
/**
* 創(chuàng)建一個(gè)延時(shí)任務(wù)ScheduledFutureTask實(shí)例。
* triggerTime方法會根據(jù)給定的延時(shí)時(shí)間delay,返回任務(wù)開始的時(shí)間。
* decorateTask方法是讓子類能夠修飾ScheduledFutureTask任務(wù)實(shí)例,本類中沒做處理。
*/
RunnableScheduledFuture<V> t = decorateTask(callable,
new ScheduledFutureTask<V>(callable,
triggerTime(delay, unit)));
// 延時(shí)執(zhí)行任務(wù)
delayedExecute(t);
return t;
}
這兩個(gè)方法的流程是一樣的,只不過一個(gè)是Runnable類型的任務(wù),一個(gè)Callable類型的任務(wù)。
- 調(diào)用triggerTime方法根據(jù)給定的延時(shí)時(shí)間delay,返回任務(wù)開始的時(shí)間。
- 創(chuàng)建一個(gè)延時(shí)任務(wù)ScheduledFutureTask實(shí)例。
- 調(diào)用decorateTask方法是讓子類能夠修飾ScheduledFutureTask任務(wù)實(shí)例。
- 調(diào)用delayedExecute(t)方法延時(shí)執(zhí)行任務(wù)。
2.2 創(chuàng)建延時(shí)定時(shí)任務(wù)
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();
/**
* 創(chuàng)建一個(gè)延時(shí)定時(shí)任務(wù)ScheduledFutureTask實(shí)例。
* triggerTime方法會根據(jù)給定的延時(shí)時(shí)間delay,返回任務(wù)開始的時(shí)間。
*/
ScheduledFutureTask<Void> sft =
new ScheduledFutureTask<Void>(command,
null,
triggerTime(initialDelay, unit),
unit.toNanos(period));
// decorateTask方法是讓子類能夠修飾ScheduledFutureTask任務(wù)實(shí)例,本類中沒做處理。
RunnableScheduledFuture<Void> t = decorateTask(command, sft);
// outerTask作用就是下一次定時(shí)執(zhí)行的任務(wù),在reExecutePeriodic方法中需要
sft.outerTask = t;
// 延時(shí)執(zhí)行任務(wù)
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();
/**
* 創(chuàng)建一個(gè)延時(shí)定時(shí)任務(wù)ScheduledFutureTask實(shí)例。
* triggerTime方法會根據(jù)給定的延時(shí)時(shí)間delay,返回任務(wù)開始的時(shí)間。
*/
ScheduledFutureTask<Void> sft =
new ScheduledFutureTask<Void>(command,
null,
triggerTime(initialDelay, unit),
unit.toNanos(-delay));
// decorateTask方法是讓子類能夠修飾ScheduledFutureTask任務(wù)實(shí)例,本類中沒做處理。
RunnableScheduledFuture<Void> t = decorateTask(command, sft);
// outerTask作用就是下一次定時(shí)執(zhí)行的任務(wù),在reExecutePeriodic方法中需要
sft.outerTask = t;
// 延時(shí)執(zhí)行任務(wù)
delayedExecute(t);
return t;
}
我們知道scheduleAtFixedRate方法是固定周期時(shí)間去執(zhí)行任務(wù),而scheduleWithFixedDelay方法是在任務(wù)完成之后,延時(shí)delay時(shí)間再去執(zhí)行任務(wù)。
但是我們發(fā)現(xiàn)這兩個(gè)方法幾乎是一模一樣的,唯一不同地就是創(chuàng)建延時(shí)定時(shí)任務(wù)ScheduledFutureTask實(shí)例時(shí),一個(gè)傳遞的是正數(shù)period,一個(gè)傳遞的是負(fù)數(shù)-delay。
- 調(diào)用triggerTime方法根據(jù)給定的延時(shí)時(shí)間delay,返回任務(wù)開始的時(shí)間。
- 創(chuàng)建一個(gè)延時(shí)定時(shí)任務(wù)ScheduledFutureTask實(shí)例。
- 調(diào)用decorateTask方法是讓子類能夠修飾ScheduledFutureTask任務(wù)實(shí)例。
- 設(shè)置outerTask,作用就是下一次定時(shí)執(zhí)行的任務(wù),在reExecutePeriodic方法中需要。
- 延時(shí)執(zhí)行任務(wù)。
2.3 triggerTime方法
/**
* 返回延時(shí)任務(wù)開始的時(shí)間
*/
private long triggerTime(long delay, TimeUnit unit) {
return triggerTime(unit.toNanos((delay < 0) ? 0 : delay));
}
/**
* 返回延時(shí)任務(wù)開始的時(shí)間。利用當(dāng)前時(shí)間加上給定的延時(shí)時(shí)間
*/
long triggerTime(long delay) {
return now() +
((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay));
}
2.4 decorateTask方法
/**
* 讓子類能夠修飾或者替換任務(wù)task。
* 這里只是簡單地返回task
*/
protected <V> RunnableScheduledFuture<V> decorateTask(
Runnable runnable, RunnableScheduledFuture<V> task) {
return task;
}
2.5 delayedExecute方法
private void delayedExecute(RunnableScheduledFuture<?> task) {
// 如果線程池不是RUNNING狀態(tài),那么調(diào)用reject(task)方法,
// 拒絕執(zhí)行任務(wù)task
if (isShutdown())
reject(task);
else {
// 將任務(wù)添加到任務(wù)隊(duì)列中,會根據(jù)任務(wù)的延時(shí)時(shí)間進(jìn)行排序
super.getQueue().add(task);
/**
* 如果線程池不是RUNNING狀態(tài),那么就判斷能不能在當(dāng)前狀態(tài)下運(yùn)行,
* 主要就是能不能在SHUTDOWN狀態(tài)下運(yùn)行。
* 如果不能在當(dāng)前狀態(tài)下運(yùn)行,那么就調(diào)用remove方法,
* 從任務(wù)隊(duì)列中移除剛剛添加的任務(wù)task。
*
* 只有移除成功了,才可以調(diào)用task.cancel(false)方法取消任務(wù),
* 否則這個(gè)延時(shí)任務(wù)task都還要執(zhí)行。
*/
if (isShutdown() &&
!canRunInCurrentRunState(task.isPeriodic()) &&
remove(task))
task.cancel(false);
else
// 預(yù)先啟動(dòng)工作線程,確保線程池中有工作線程。
ensurePrestart();
}
}
這個(gè)方法的主要作用就是將任務(wù)添加到任務(wù)隊(duì)列中,因?yàn)檫@里任務(wù)隊(duì)列是優(yōu)先級隊(duì)列DelayedWorkQueue,它會根據(jù)任務(wù)的延時(shí)時(shí)間進(jìn)行排序。
- 如果線程池不是RUNNING狀態(tài),不能執(zhí)行延時(shí)任務(wù)task,那么調(diào)用reject(task)方法,拒絕執(zhí)行任務(wù)task。
- 將任務(wù)添加到任務(wù)隊(duì)列中,會根據(jù)任務(wù)的延時(shí)時(shí)間進(jìn)行排序。
- 因?yàn)槭嵌嗑€程并發(fā)環(huán)境,就必須判斷在添加任務(wù)的過程中,線程池狀態(tài)是否被別的線程更改了,那么就可能要取消任務(wù)了。
- 將任務(wù)添加到任務(wù)隊(duì)列后,還要確保線程池中有工作線程,不然任務(wù)也不為執(zhí)行。所以ensurePrestart()方法預(yù)先啟動(dòng)工作線程,確保線程池中有工作線程。
與ThreadPoolExecutor類中execute方法執(zhí)行任務(wù)方法不同:
- 因?yàn)槭茄訒r(shí)任務(wù)task,所以不能將任務(wù)當(dāng)成工作線程第一個(gè)任務(wù),只能將任務(wù)添加到任務(wù)隊(duì)列中,等待著工作線程來執(zhí)行。
- 任務(wù)隊(duì)列DelayedWorkQueue容量幾乎是無限的,所以也不需要最大池。除非核心池?cái)?shù)量是0,那么必須創(chuàng)建一個(gè)工作線程來運(yùn)行任務(wù),否則線程池的線程數(shù)不可能超過核心池?cái)?shù)量。
- 當(dāng)線程池狀態(tài)被別的線程改變時(shí),取消任務(wù)的判斷條件不同。當(dāng)線程池狀態(tài)不是RUNNING,而且不能在當(dāng)前狀態(tài)下運(yùn)行,那么就調(diào)用remove方法,移除剛剛添加的任務(wù)task。只有移除任務(wù)成功,才可以調(diào)用task.cancel(false)方法取消任務(wù),否則這個(gè)延時(shí)任務(wù)task都還要執(zhí)行。
2.6 canRunInCurrentRunState方法
// 判斷能不能在當(dāng)前狀態(tài)下運(yùn)行
boolean canRunInCurrentRunState(boolean periodic) {
// 調(diào)用父類ThreadPoolExecutor中的isRunningOrShutdown方法
return isRunningOrShutdown(periodic ?
continueExistingPeriodicTasksAfterShutdown :
executeExistingDelayedTasksAfterShutdown);
}
/**
* 是ThreadPoolExecutor中的方法
* @param shutdownOK 表示線程池能在SHUTDOWN狀態(tài)下運(yùn)行
*/
final boolean isRunningOrShutdown(boolean shutdownOK) {
// 線程狀態(tài)
int rs = runStateOf(ctl.get());
// 當(dāng)線程是RUNNING狀態(tài),或者是SHUTDOWN狀態(tài)且shutdownOK也為true
return rs == RUNNING || (rs == SHUTDOWN && shutdownOK);
}
canRunInCurrentRunState方法就是返回線程池能不能在當(dāng)前狀態(tài)下運(yùn)行。
注: continueExistingPeriodicTasksAfterShutdown與executeExistingDelayedTasksAfterShutdown都是提供給外部設(shè)置。
2.7 ensurePrestart方法
void ensurePrestart() {
// 線程池中的線程數(shù)量
int wc = workerCountOf(ctl.get());
// 如果小于核心池?cái)?shù)量,就創(chuàng)建新的工作線程
if (wc < corePoolSize)
addWorker(null, true);
// 說明corePoolSize數(shù)量是0,必須創(chuàng)建一個(gè)工作線程來執(zhí)行任務(wù)
else if (wc == 0)
addWorker(null, false);
}
ensurePrestart方法作用:預(yù)先啟動(dòng)工作線程,確保線程池中有工作線程。
三. ScheduledFutureTask類
ScheduledFutureTask是一個(gè)延時(shí)定時(shí)任務(wù),它可以返回任務(wù)剩余延時(shí)時(shí)間,可以被周期性地執(zhí)行。
3.1 重要成員屬性
/** 是一個(gè)序列,每次創(chuàng)建任務(wù)的時(shí)候,都會自增。 */
private final long sequenceNumber;
/** 任務(wù)能夠開始執(zhí)行的時(shí)間 */
private long time;
/**
* 任務(wù)周期執(zhí)行的時(shí)間
* 0表示不是一個(gè)周期定時(shí)任務(wù)
* 正數(shù)表示固定周期時(shí)間去執(zhí)行任務(wù)
* 負(fù)數(shù)表示任務(wù)完成之后,延時(shí)period時(shí)間再去執(zhí)行任務(wù)
*/
private final long period;
/** 表示再次執(zhí)行的任務(wù),在reExecutePeriodic中調(diào)用 */
RunnableScheduledFuture<V> outerTask = this;
/**
* 表示在任務(wù)隊(duì)列中的索引位置,用來支持快速從隊(duì)列中刪除任務(wù)。
*/
int heapIndex;
屬性說明:
- sequenceNumber: 是一個(gè)序列,每次創(chuàng)建任務(wù)的時(shí)候,都會自增。
- time: 任務(wù)能夠開始執(zhí)行的時(shí)間。
- period: 任務(wù)周期執(zhí)行的時(shí)間。0表示不是一個(gè)周期定時(shí)任務(wù)。
- outerTask: 表示再次執(zhí)行的任務(wù),在reExecutePeriodic中調(diào)用
- heapIndex: 表示在任務(wù)隊(duì)列中的索引位置,用來支持快速從隊(duì)列中刪除任務(wù)。
3.2 構(gòu)造函數(shù)
3.2.1 創(chuàng)建延時(shí)任務(wù)
/**
* 創(chuàng)建延時(shí)任務(wù)
*/
ScheduledFutureTask(Runnable r, V result, long ns) {
// 調(diào)用父類的方法
super(r, result);
// 任務(wù)開始的時(shí)間
this.time = ns;
// period是0,不是一個(gè)周期定時(shí)任務(wù)
this.period = 0;
// 每次創(chuàng)建任務(wù)的時(shí)候,sequenceNumber都會自增
this.sequenceNumber = sequencer.getAndIncrement();
}
/**
* 創(chuàng)建延時(shí)任務(wù)
*/
ScheduledFutureTask(Callable<V> callable, long ns) {
// 調(diào)用父類的方法
super(callable);
// 任務(wù)開始的時(shí)間
this.time = ns;
// period是0,不是一個(gè)周期定時(shí)任務(wù)
this.period = 0;
// 每次創(chuàng)建任務(wù)的時(shí)候,sequenceNumber都會自增
this.sequenceNumber = sequencer.getAndIncrement();
}
3.2.2 創(chuàng)建延時(shí)定時(shí)任務(wù)
/**
* 創(chuàng)建延時(shí)定時(shí)任務(wù)
*/
ScheduledFutureTask(Runnable r, V result, long ns, long period) {
// 調(diào)用父類的方法
super(r, result);
// 任務(wù)開始的時(shí)間
this.time = ns;
// 周期定時(shí)時(shí)間
this.period = period;
// 每次創(chuàng)建任務(wù)的時(shí)候,sequenceNumber都會自增
this.sequenceNumber = sequencer.getAndIncrement();
}
3.3 運(yùn)行任務(wù)run方法
public void run() {
// 是否是周期任務(wù)
boolean periodic = isPeriodic();
// 如果不能在當(dāng)前狀態(tài)下運(yùn)行,那么就要取消任務(wù)
if (!canRunInCurrentRunState(periodic))
cancel(false);
// 如果只是延時(shí)任務(wù),那么就調(diào)用run方法,運(yùn)行任務(wù)。
else if (!periodic)
ScheduledFutureTask.super.run();
// 如果是周期定時(shí)任務(wù),調(diào)用runAndReset方法,運(yùn)行任務(wù)。
// 這個(gè)方法不會改變?nèi)蝿?wù)的狀態(tài),所以可以反復(fù)執(zhí)行。
else if (ScheduledFutureTask.super.runAndReset()) {
// 設(shè)置周期任務(wù)下一次執(zhí)行的開始時(shí)間time
setNextRunTime();
// 重新執(zhí)行任務(wù)outerTask
reExecutePeriodic(outerTask);
}
}
這個(gè)方法會在ThreadPoolExecutor的runWorker方法中調(diào)用,而且這個(gè)方法調(diào)用,說明肯定已經(jīng)到了任務(wù)的開始時(shí)間time了。
- 先判斷當(dāng)前線程狀態(tài)能不能運(yùn)行任務(wù),如果不能,就調(diào)用cancel()方法取消本任務(wù)。
- 如果任務(wù)只是一個(gè)延時(shí)任務(wù),那么調(diào)用父類的run()運(yùn)行任務(wù),改變?nèi)蝿?wù)的狀態(tài),表示任務(wù)已經(jīng)運(yùn)行完成了。
- 如果任務(wù)只是一個(gè)周期定時(shí)任務(wù),那么就任務(wù)必須能夠反復(fù)執(zhí)行,那么就不能調(diào)用run()方法,它會改變?nèi)蝿?wù)的狀態(tài)。而是調(diào)用runAndReset()方法,只是簡單地運(yùn)行任務(wù),而不會改變?nèi)蝿?wù)狀態(tài)。
- 設(shè)置周期任務(wù)下一次執(zhí)行的開始時(shí)間time,并重新執(zhí)行任務(wù)。
setNextRunTime設(shè)置任務(wù)下一次執(zhí)行的開始時(shí)間time的方法:
/**
* 設(shè)置任務(wù)下一次執(zhí)行的開始時(shí)間time
*/
private void setNextRunTime() {
// 周期時(shí)間
long p = period;
if (p > 0)
time += p;
else
time = triggerTime(-p);
}
我們發(fā)現(xiàn)當(dāng)p大于0的時(shí)候,調(diào)用time += p,那么就可能出現(xiàn)計(jì)算后的time可能小于當(dāng)前時(shí)間,因?yàn)槿蝿?wù)執(zhí)行時(shí)間超過了周期時(shí)間p,所以將這個(gè)任務(wù)添加到任務(wù)隊(duì)列中,它就會立即執(zhí)行。
而當(dāng)p小于0的時(shí)候,調(diào)用time = triggerTime(-p)方法,就是在當(dāng)前時(shí)間上,再加上-p的延時(shí)時(shí)間,所以這個(gè)任務(wù)添加到任務(wù)隊(duì)列中,必須延時(shí)-p時(shí)間后,才能執(zhí)行。
reExecutePeriodic重新執(zhí)行任務(wù)的方法:
/**
* 重新執(zhí)行任務(wù)task
*/
void reExecutePeriodic(RunnableScheduledFuture<?> task) {
// 判斷當(dāng)前線程池狀態(tài)能不能運(yùn)行任務(wù)
if (canRunInCurrentRunState(true)) {
// 將任務(wù)添加到任務(wù)隊(duì)列,會根據(jù)任務(wù)延時(shí)時(shí)間進(jìn)行排序
super.getQueue().add(task);
// 如果線程池狀態(tài)改變了,當(dāng)前狀態(tài)不能運(yùn)行任務(wù),那么就嘗試移除任務(wù),
// 移除成功,就取消任務(wù)。
if (!canRunInCurrentRunState(true) && remove(task))
task.cancel(false);
else
// 預(yù)先啟動(dòng)工作線程,確保線程池中有工作線程。
ensurePrestart();
}
}
這個(gè)方法與delayedExecute方法很像,都是將任務(wù)添加到任務(wù)隊(duì)列中。
- 如果當(dāng)前線程池狀態(tài)能夠運(yùn)行任務(wù),那么任務(wù)添加到任務(wù)隊(duì)列。
- 如果在在添加任務(wù)的過程中,線程池狀態(tài)是否被別的線程更改了,那么就要進(jìn)行判斷,是否需要取消任務(wù)。
- 調(diào)用ensurePrestart()方法,預(yù)先啟動(dòng)工作線程,確保線程池中有工作線程。
3.4 其他重要方法
3.4.1 取消任務(wù)
public boolean cancel(boolean mayInterruptIfRunning) {
// 調(diào)用父類的cancel方法取消任務(wù)
boolean cancelled = super.cancel(mayInterruptIfRunning);
// 將任務(wù)從任務(wù)隊(duì)列中移除
if (cancelled && removeOnCancel && heapIndex >= 0)
remove(this);
return cancelled;
}
3.4.2 getDelay方法
// 返回任務(wù)剩余延時(shí)時(shí)間
public long getDelay(TimeUnit unit) {
return unit.convert(time - now(), NANOSECONDS);
}
3.4.3 compareTo方法
public int compareTo(Delayed other) {
if (other == this)
return 0;
// 如果是ScheduledFutureTask實(shí)例
if (other instanceof ScheduledFutureTask) {
ScheduledFutureTask<?> x = (ScheduledFutureTask<?>)other;
// 比較任務(wù)開始時(shí)間
long diff = time - x.time;
if (diff < 0)
return -1;
else if (diff > 0)
return 1;
// 比較那么任務(wù)是新創(chuàng)建的,因?yàn)樾聞?chuàng)建的sequenceNumber小一點(diǎn)。
else if (sequenceNumber < x.sequenceNumber)
return -1;
else
return 1;
}
// 比較任務(wù)的剩余延時(shí)時(shí)間
long diff = getDelay(NANOSECONDS) - other.getDelay(NANOSECONDS);
return (diff < 0) ? -1 : (diff > 0) ? 1 : 0;
}
3.4.4 isPeriodic方法
/**
* 是否是周期定時(shí)任務(wù)
*/
public boolean isPeriodic() {
return period != 0;
}
四. 創(chuàng)建延時(shí)定時(shí)線程池
4.1 構(gòu)造函數(shù)
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
public ScheduledThreadPoolExecutor(int corePoolSize,
ThreadFactory threadFactory) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue(), threadFactory);
}
public ScheduledThreadPoolExecutor(int corePoolSize,
RejectedExecutionHandler handler) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue(), handler);
}
public ScheduledThreadPoolExecutor(int corePoolSize,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue(), threadFactory, handler);
}
都是調(diào)用父類ThreadPoolExecutor構(gòu)造函數(shù)的方法,唯一要注意的地方就是任務(wù)隊(duì)列只能是DelayedWorkQueue實(shí)例,用戶沒有辦法更換ScheduledThreadPoolExecutor的任務(wù)隊(duì)列屬性。
4.2 創(chuàng)建單個(gè)線程的定時(shí)線程池
public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
return new DelegatedScheduledExecutorService
(new ScheduledThreadPoolExecutor(1));
}
public static ScheduledExecutorService newSingleThreadScheduledExecutor(
ThreadFactory threadFactory) {
return new DelegatedScheduledExecutorService
(new ScheduledThreadPoolExecutor(1, threadFactory));
}
4.3 創(chuàng)建固定數(shù)量的定時(shí)線程池
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public static ScheduledExecutorService newScheduledThreadPool(
int corePoolSize, ThreadFactory threadFactory) {
return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}