實現計劃框架 在上一節
我們學習了如何使用計劃框架
並將它與 Java 定時器框架進行了比較
下面
我將向您展示如何實現這個框架
除了 清單
中展示的 ScheduleIterator 接口
構成這個框架的還有另外兩個類 —— Scheduler 和 SchedulerTask
這些類實際上在內部使用 Timer 和 SchedulerTask
因為計劃其實就是一系列的單次定時器
清單
和
顯示了這兩個類的源代碼
清單
Scheduler
package org
tiling
scheduling;
import java
util
Date;
import java
util
Timer;
import java
util
TimerTask;
public class Scheduler {
class SchedulerTimerTask extends TimerTask {
private SchedulerTask schedulerTask;
private ScheduleIterator iterator;
public SchedulerTimerTask(SchedulerTask schedulerTask
ScheduleIterator iterator) {
this
schedulerTask = schedulerTask;
erator = iterator;
}
public void run() {
schedulerTask
run();
reschedule(schedulerTask
iterator);
}
}
private final Timer timer = new Timer();
public Scheduler() {
}
public void cancel() {
timer
cancel();
}
public void schedule(SchedulerTask schedulerTask
ScheduleIterator iterator) {
Date time = iterator
next();
if (time == null) {
schedulerTask
cancel();
} else {
synchronized(schedulerTask
lock) {
if (schedulerTask
state != SchedulerTask
VIRGIN) {
throw new IllegalStateException(
Task already
scheduled
+
or cancelled
);
}
schedulerTask
state = SchedulerTask
SCHEDULED;
schedulerTask
timerTask =
new SchedulerTimerTask(schedulerTask
iterator);
timer
schedule(schedulerTask
timerTask
time);
}
}
}
private void reschedule(SchedulerTask schedulerTask
ScheduleIterator iterator) {
Date time = iterator
next();
if (time == null) {
schedulerTask
cancel();
} else {
synchronized(schedulerTask
lock) {
if (schedulerTask
state != SchedulerTask
CANCELLED) {
schedulerTask
timerTask =
new SchedulerTimerTask(schedulerTask
iterator);
timer
schedule(schedulerTask
timerTask
time);
}
}
}
}
}
清單
顯示了 SchedulerTask 類的源代碼
package org
tiling
scheduling;
import java
util
TimerTask;
public abstract class SchedulerTask implements Runnable {
final Object lock = new Object();
int state = VIRGIN;
static final int VIRGIN =
;
static final int SCHEDULED =
;
static final int CANCELLED =
;
TimerTask timerTask;
protected SchedulerTask() {
}
public abstract void run();
public boolean cancel() {
synchronized(lock) {
if (timerTask != null) {
timerTask
cancel();
}
boolean result = (state == SCHEDULED);
state = CANCELLED;
return result;
}
}
public long scheduledExecutionTime() {
synchronized(lock) {
return timerTask == null ?
: timerTask
scheduledExecutionTime();
}
}
}
就像煮蛋計時器
Scheduler 的每一個實例都擁有 Timer 的一個實例
用於提供底層計劃
Scheduler 並沒有像實現煮蛋計時器時那樣使用一個單次定時器
它將一組單次定時器串接在一起
以便在由 ScheduleIterator 指定的各個時間執行 SchedulerTask 類
考慮 Scheduler 上的 public schedule() 方法 —— 這是計劃的入口點
因為它是客戶調用的方法(在 取消任務 一節中將描述僅有的另一個 public 方法 cancel())
通過調用 ScheduleIterator 接口的 next()
發現第一次執行 SchedulerTask 的時間
然後通過調用底層 Timer 類的單次 schedule() 方法
啟動計劃在這一時刻執行
為單次執行提供的 TimerTask 對象是嵌入的 SchedulerTimerTask 類的一個實例
它包裝了任務和迭代器(iterator)
在指定的時間
調用嵌入類的 run() 方法
它使用包裝的任務和迭代器引用以便重新計劃任務的下一次執行
reschedule() 方法與 schedule() 方法非常相似
只不過它是 private 的
並且執行一組稍有不同的 SchedulerTask 狀態檢查
重新計劃過程反復重復
為每次計劃執行構造一個新的嵌入類實例
直到任務或者調度程序被取消(或者 JVM 關閉)
類似於 TimerTask
SchedulerTask 在其生命周期中要經歷一系列的狀態
創建後
它處於 VIRGIN 狀態
這表明它從沒有計劃過
計劃以後
它就變為 SCHEDULED 狀態
再用下面描述的方法之一取消任務後
它就變為 CANCELLED 狀態
管理正確的狀態轉變 —— 如保證不對一個非 VIRGIN 狀態的任務進行兩次計劃 —— 增加了 Scheduler 和 SchedulerTask 類的復雜性
在進行可能改變任務狀態的操作時
代碼必須同步任務的鎖對象
取消任務 取消計劃任務有三種方式
第一種是調用 SchedulerTask 的 cancel() 方法
這很像調用 TimerTask 的 cancel()方法
任務再也不會運行了
不過已經運行的任務仍會運行完成
cancel() 方法的返回值是一個布爾值
表示如果沒有調用 cancel() 的話
計劃的任務是否還會運行
更准確地說
如果任務在調用 cancel() 之前是 SCHEDULED 狀態
那麼它就返回 true
如果試圖再次計劃一個取消的(甚至是已計劃的)任務
那麼 Scheduler 就會拋出一個 IllegalStateException
取消計劃任務的第二種方式是讓 ScheduleIterator 返回 null
這只是第一種方式的簡化操作
因為 Scheduler 類調用 SchedulerTask 類的 cancel()方法
如果您想用迭代器而不是任務來控制計劃停止時間時
就用得上這種取消任務的方式了
第三種方式是通過調用其 cancel() 方法取消整個 Scheduler
這會取消調試程序的所有任務
並使它不能再計劃任何任務
擴展 cron 實用程序 可以將計劃框架比作 UNIX 的 cron 實用程序
只不過計劃次數的規定是強制性而不是聲明性的
例如
在 AlarmClock 實現中使用的 DailyIterator 類
它的計劃與 cron 作業的計劃相同
都是由以
* * * 開始的 crontab 項指定的(這些字段分別指定分鐘
小時
日
月和星期)
不過
計劃框架比 cron 更靈活
想像一個在早晨打開熱水的 HeatingController 應用程序
我想指示它
在每個工作日上午
:
打開熱水
在周未上午
:
打開熱水
使用 cron
我需要兩個 crontab 項(
* *
和
* *
)
而使用 ScheduleIterator 的解決方案更簡潔一些
因為我可以使用復合(composition)來定義單一迭代器
清單
顯示了其中的一種方法
清單
用復合定義單一迭代器
int[] weekdays = new int[] {
Calendar
MONDAY
Calendar
TUESDAY
Calendar
WEDNESDAY
Calendar
THURSDAY
Calendar
FRIDAY
};
int[] weekend = new int[] {
Calendar
SATURDAY
Calendar
SUNDAY
};
ScheduleIterator i = new CompositeIterator(
new ScheduleIterator[] {
new RestrictedDailyIterator(
weekdays)
new RestrictedDailyIterator(
weekend)
}
);
RestrictedDailyIterator 類很像 DailyIterator
只不過它限制為只在一周的特定日子裡運行
而一個 CompositeIterator 類取得一組 ScheduleIterators
並將日期正確排列到單個計劃中
有許多計劃是 cron 無法生成的
但是 ScheduleIterator 實現卻可以
例如
每個月的最後一天
描述的計劃可以用標准 Java 日歷算法來實現(用 Calendar 類)
From:http://tw.wingwit.com/Article/program/Java/JSP/201311/19382.html