所有類型的 Java 應用程序一般都需要計劃重復執行的任務
企業應用程序需要計劃每日的日志或者晚間批處理過程
一個 J
SE 或者 J
ME 日歷應用程序需要根據用戶的約定計劃鬧鈴時間
不過
標准的調度類 Timer 和 TimerTask 沒有足夠的靈活性
無法支持通常需要的計劃任務類型
在本文中
Java 開發人員 Tom White 向您展示了如何構建一個簡單通用的計劃框架
以用於執行任意復雜的計劃任務
我將把 java
util
Timer 和 java
util
TimerTask 統稱為 Java 計時器框架
它們使程序員可以很容易地計劃簡單的任務(注意這些類也可用於 J
ME 中)
在 Java
SDK
Standard Edition
Version
中引入這個框架之前
開發人員必須編寫自己的調度程序
這需要花費很大精力來處理線程和復雜的 Object
wait() 方法
不過
Java 計時器框架沒有足夠的能力來滿足許多應用程序的計劃要求
甚至一項需要在每天同一時間重復執行的任務
也不能直接使用 Timer 來計劃
因為在夏令時開始和結束時會出現時間跳躍
本文展示了一個通用的 Timer 和 TimerTask 計劃框架
從而允許更靈活的計劃任務
這個框架非常簡單 —— 它包括兩個類和一個接口 —— 並且容易掌握
如果您習慣於使用 Java 定時器框架
那麼您應該可以很快地掌握這個計劃框架
計劃單次任務 計劃框架建立在 Java 定時器框架類的基礎之上
因此
在解釋如何使用計劃框架以及如何實現它之前
我們將首先看看如何用這些類進行計劃
想像一個煮蛋計時器
在數分鐘之後(這時蛋煮好了)它會發出聲音提醒您
清單
中的代碼構成了一個簡單的煮蛋計時器的基本結構
它用 Java 語言編寫
清單
EggTimer 類
package org
tiling
scheduling
examples;
import java
util
Timer;
import java
util
TimerTask;
public class EggTimer {
private final Timer timer = new Timer();
private final int minutes;
public EggTimer(int minutes) {
this
minutes = minutes;
}
public void start() {
timer
schedule(new TimerTask() {
public void run() {
playSound();
timer
cancel();
}
private void playSound() {
System
out
println(
Your egg is ready!
);
// Start a new thread to play a sound
}
}
minutes *
*
);
}
public static void main(String[] args) {
EggTimer eggTimer = new EggTimer(
);
eggTimer
start();
}
}
EggTimer 實例擁有一個 Timer 實例
用於提供必要的計劃
用 start() 方法啟動煮蛋計時器後
它就計劃了一個 TimerTask
在指定的分鐘數之後執行
時間到了
Timer 就在後台調用 TimerTask 的 start() 方法
這會使它發出聲音
在取消計時器後這個應用程序就會中止
計劃重復執行的任務 通過指定一個固定的執行頻率或者固定的執行時間間隔
Timer 可以對重復執行的任務進行計劃
不過
有許多應用程序要求更復雜的計劃
例如
每天清晨在同一時間發出叫醒鈴聲的鬧鐘不能簡單地使用固定的計劃頻率
毫秒(
小時)
因為在鐘撥快或者撥慢(如果您的時區使用夏令時)的那些天裡
叫醒可能過晚或者過早
解決方案是使用日歷算法計算每日事件下一次計劃發生的時間
而這正是計劃框架所支持的
考慮清單
中的 AlarmClock 實現
清單
AlarmClock 類
package org
tiling
scheduling
examples;
import java
text
SimpleDateFormat;
import java
util
Date;
import org
tiling
scheduling
Scheduler;
import org
tiling
scheduling
SchedulerTask;
import org
tiling
scherators
DailyIterator;
public class AlarmClock {
private final Scheduler scheduler = new Scheduler();
private final SimpleDateFormat dateFormat =
new SimpleDateFormat(
dd MMM yyyy HH:mm:ss
SSS
);
private final int hourOfDay
minute
second;
public AlarmClock(int hourOfDay
int minute
int second) {
this
hourOfDay = hourOfDay;
this
minute = minute;
this
second = second;
}
public void start() {
scheduler
schedule(new SchedulerTask() {
public void run() {
soundAlarm();
}
private void soundAlarm() {
System
out
println(
Wake up!
+
It
s
+ dateFormat
format(new Date()));
// Start a new thread to sound an alarm
}
}
new DailyIterator(hourOfDay
minute
second));
}
public static void main(String[] args) {
AlarmClock alarmClock = new AlarmClock(
);
alarmClock
start();
}
}
注意這段代碼與煮蛋計時器應用程序非常相似
AlarmClock 實例擁有一個 Scheduler (而不是 Timer)實例
用於提供必要的計劃
啟動後
這個鬧鐘對 SchedulerTask (而不是 TimerTask)進行調度用以發出報警聲
這個鬧鐘不是計劃一個任務在固定的延遲時間後執行
而是用 DailyIterator 類描述其計劃
在這裡
它只是計劃任務在每天上午
:
執行
下面是一個正常運行情況下的輸出
Wake up! It
s
Aug
:
:
Wake up! It
s
Aug
:
:
Wake up! It
s
Aug
:
:
Wake up! It
s
Aug
:
:
Wake up! It
s
Aug
:
:
DailyIterator 實現了 ScheduleIterator
這是一個將 SchedulerTask 的計劃執行時間指定為一系列 java
util
Date 對象的接口
然後 next() 方法按時間先後順序迭代 Date 對象
返回值 null 會使任務取消(即它再也不會運行)—— 這樣的話
試圖再次計劃將會拋出一個異常
清單
包含 ScheduleIterator 接口
清單
ScheduleIterator 接口
package org
tiling
scheduling;
import java
util
Date;
public interface ScheduleIterator {
public Date next();
}
DailyIterator 的 next() 方法返回表示每天同一時間(上午
:
)的 Date 對象
如清單
所示
所以
如果對新構建的 next() 類調用 next()
那麼將會得到傳遞給構造函數的那個日期當天或者後面一天的
:
AM
再次調用 next() 會返回後一天的
:
AM
如此重復
為了實現這種行為
DailyIterator 使用了 java
util
Calendar 實例
構造函數會在日歷中加上一天
對日歷的這種設置使得第一次調用 next() 會返回正確的 Date
注意代碼沒有明確地提到夏令時修正
因為 Calendar 實現(在本例中是 GregorianCalendar)負責對此進行處理
所以不需要這樣做
清單
DailyIterator 類
package org
tiling
scherators;
import org
tiling
scheduling
ScheduleIterator;
import java
util
Calendar;
import java
util
Date;
/**
* A DailyIterator class returns a sequence of dates on subsequent days
* representing the same time each day
*/
public class DailyIterator implements ScheduleIterator {
private final int hourOfDay
minute
second;
private final Calendar calendar = Calendar
getInstance();
public DailyIterator(int hourOfDay
int minute
int second) {
this(hourOfDay
minute
second
new Date());
}
public DailyIterator(int hourOfDay
int minute
int second
Date date) {
this
hourOfDay = hourOfDay;
this
minute = minute;
this
second = second;
calendar
setTime(date);
calendar
set(Calendar
HOUR_OF_DAY
hourOfDay);
calendar
set(Calendar
MINUTE
minute);
calendar
set(Calendar
SECOND
second);
calendar
set(Calendar
MILLISECOND
);
if (!calendar
getTime()
before(date)) {
calendar
add(Calendar
DATE
);
}
}
public Date next() {
calendar
add(Calendar
DATE
);
return calendar
getTime();
}
}
From:http://tw.wingwit.com/Article/program/Java/JSP/201311/19734.html