Java 中要定時執行某個動作,有三種選擇:
1、Timer 和 TimerTask
2、ScheduledExecutorService
3、quartz 套件
原本我是用 1 的方法來實作定時執行,但後來遇到 Timer 的 thread 難以控制的問題
如果定時執行到一半突然必須強制關閉時,Timer 很難做到讓我找出它的 thread 並且關掉
在查了一些資料後看到這篇文章:Java Timer vs ExecutorService?
其中回應裡有一段「ScheduledThreadPoolExecutor can be configured with any number of threads. Furthermore, you have full control over created threads, if you want (by providing ThreadFactory)」
而 quartz 因為不明原因把網路上找到的 sample code 貼上去以後程式就爆了
而且有看到有文章說 ScheduledExecutorService 是比較底層的 API,雖然很多事情要自己做
但也因此能夠自己對 Thread 有比較完整的控制權
因此最後是決定改用 ScheduledExecutorService 來實作定時執行。
指定時間只執行一次:
import java.util.Calendar; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class OneShot{ private ScheduledExecutorService scheduler; public OneShot() { scheduler = Executors.newScheduledThreadPool(1); } public void addTask (long updateTime) { long delay = 0; long currentTime = Calendar.getInstance().getTimeInMillis(); // 指定的時間還沒到就排程執行 if(updateTime > currentTime) scheduler.schedule(new Shot(), delay, TimeUnit.MILLISECONDS); } private class Shot implements Runnable { public Shot() {} public void run() { ................. } } }
排程定時執行:
import java.util.Calendar; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; public class ScheduleTask { private ScheduledExecutorService scheduler; public ScheduleTask() { scheduler = Executors.newSingleThreadScheduledExecutor(); } public void addTask (long delay, long breakTime) { scheduler.scheduleWithFixedDelay(new Shot(), delay, breakTime, TimeUnit.MILLISECONDS); } private class Shot implements Runnable { public Shot() {} public void run() { ................. } } }
要執行時只要實例化之後呼叫 AddTask() 並且給予適當的參數即可。
// 執行一次 OneShot oneShot = new OneShot(); Calendar cal = Calendar.getInstance(); cal.add(Calendar.SECOND, 10); // 設定 10 秒後執行 oneShot.addTask(cal.getTimeInMillis()); ScheduleTask schedule = new ScheduleTask(); schedule.addTask(1000, 60000); // 排程 1 秒後開始,每分鐘執行一次
目前還沒開始做 ThreadFactory,不過要控制 Thread 應該是需要 ThreadFactory 來解決。
2012.1.11 更新:請參考續篇 Java 定時執行 (2):將 ExecutorService 產生的 Thread 加入 ThreadGroup
參考資料:
在Timer和ScheduledExecutorService间决择
How to use ThreadFactory in Java
ThreadFactory usage in Java
沒有留言:
張貼留言