2009-03-05 16 views
7

我的程序有一個名爲Scheduler的組件,它允許其他組件註冊他們想要回調的時間點。這應該很像Unix的cron服務,我。即你告訴調度員「每過完整一小時十分鐘就通知我」。處理「回調」計劃執行的Java庫類?

我知道Java中沒有真正的回調。

這是我的方法,有沒有一個庫已經做這個東西?隨意提出改進建議。

註冊呼叫調度通行證:

  • 包括小時,分,秒,年,月,DOM,陶氏,每個項目可能是不確定的時間說明,意爲「執行它的每一個小時/分鐘等。 「 (就像crontabs一樣)
  • 一個包含數據的對象,這些數據將告知調用對象當Scheduler通知它該做什麼。調度程序不處理這些數據,只是將其存儲並在通知後將其傳回。
  • 到調用對象

在啓動時的基準,或新的註冊請求後,調度與當前系統時間,並檢查日曆對象開始,如果有匹配數據庫中這一點,任何項時間點。如果有,它們將被執行,並且過程重新開始。如果沒有,則Calendar對象中的時間將增加1秒,並重新檢查entreis。這一直重複,直到有一個或多個條目匹配(es)。 (離散事件模擬)

調度程序然後會記住時間戳,睡眠和每秒喚醒以檢查它是否已經存在。如果它恰好醒來並且時間已經過去,它會重新開始,同樣如果時間到了並且作業已經執行完畢。


編輯:感謝您指出我石英。然而,我正在尋找更小的東西。

回答

4

如果您的需求很簡單,可以考慮使用java.util.Timer

public class TimerDemo { 

    public static void main(String[] args) { 
    // non-daemon threads prevent termination of VM 
    final boolean isDaemon = false; 
    Timer timer = new Timer(isDaemon); 

    final long threeSeconds = 3 * 1000; 
    final long delay = 0; 
    timer.schedule(new HelloTask(), delay, threeSeconds); 

    Calendar calendar = Calendar.getInstance(); 
    calendar.add(Calendar.MINUTE, 1); 
    Date oneMinuteFromNow = calendar.getTime(); 

    timer.schedule(new KillTask(timer), oneMinuteFromNow); 
    } 

    static class HelloTask extends TimerTask { 
    @Override 
    public void run() { 
     System.out.println("Hello"); 
    } 
    } 

    static class KillTask extends TimerTask { 

    private final Timer timer; 

    public KillTask(Timer timer) { 
     this.timer = timer; 
    } 

    @Override 
    public void run() { 
     System.out.println("Cancelling timer"); 
     timer.cancel(); 
    } 
    } 

} 

由於一直noted,該ExecutorServicejava.util.concurrent提供了一個更豐富的API,如果你需要的話。

4

Quartz是這個領域的重要而顯而易見的強國,但也有一些可供選擇的探索方式。

Cron4j是一個體面的庫,比Quartz稍微輕一點。它提供了很好的文檔,並會做你想做的。

也許更有趣的是,如果你想使用符合Java的併發庫(尤其是執行人和ScheduledExecutors)更好,然後HA-JDBCCronExecutorService接口,通過其CronThreadPoolExecutor實施庫。現在,有趣的是,它依賴於Quartz(提供CronExpression類),但是我發現這兩者合作比單獨使用Quartz更好。如果你不想要大的依賴關係,那麼可以很容易地從Quartz和HA-JDBC中提取一些這樣的類來實現這一點。由於你想要更小的東西(只是注意到你的編輯),從Quartz中抓取CronExpression,以及上面提到的兩個HA-JDBC類。這將做到這一點。

5

如果您的物體完全知道他們希望執行的各個時間點,那麼您可以使用java.util.concurrent.ScheduledExecutorService。然後,他們簡單的調用:

ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(2); 
long timeToExecute = ... //read from DB? use CronTrigger? 
long delayToExecution = timeToExecute - System.currentTimeMillis(); 
scheduler.schedule(aRunnable, delayToExecution, TimeUnit.MILLISECONDS); 

你只需要使用Quartz如果您想要調度程序本身,如「執行每5秒」處理功能,或者如果你想複雜的行爲會讓你錯過處決,或持續的執行審計跟蹤。

您實際上可以簡單地重複使用Quartz的CronTrigger類來獲得「下一次執行時間」。這個類是完全獨立的,不依賴於從Quartz「上下文」中調用。一旦你的下一個執行時間爲Datelong,你可以使用Java ScheduledExecutorService如上

0

不能相信java.util.Timer被投票作爲答案。石英是一個更好的選擇。

與java.util.Timer相比,Quartus的一大優點是可以將石英作業存儲在數據庫中。結果一個jvm可以安排,另一個可以執行。另外(顯然),請求在jvm重新啓動時存活。

+0

是的,但我需要的東西非常簡單,沒有額外的依賴關係。無論如何,我的應用程序已經處理了持久性,調度程序本身並不需要它。儘管我的列表中有Quartz,我以後需要更多的權力。 – 2009-03-07 09:14:46

0

也許更有趣的是,如果你想使用符合Java的併發庫(尤其是執行人和ScheduledExecutors),那麼HA-JDBC具有CronExecutorService接口,通過其CronThreadPoolExecutor實施效果較好的庫。現在,有趣的是,它依賴於Quartz(提供CronExpression類),但是我發現這兩者合作比單獨使用Quartz更好。如果你不想要大的依賴關係,那麼可以很容易地從Quartz和HA-JDBC中提取一些這樣的類來實現這一點。

我只是想說我試着提取這些類,它的工作!我需要這三個類:

  • CronExpression(石英)
  • CronThreadPoolExecutor(HA-JDBC)
  • DaemonThreadFactory(HA-JDBC)

而且我只有做這些小的調整:

  • 從CronThreadPoolExecutor刪除記錄器(它已創建但從未使用過)
  • 搬離CronTrigger不斷YEAR_TO_GIVEUP_SCHEDULING_AT到CronExpression

我很高興,我沒有依賴關係的糾結卡住拉。恭喜集體作家!

它一直像冠軍一樣工作。

1

我強烈推薦cron4j(已經提到過)Quartz,除非你絕對需要一些更先進和更復雜的Quartz功能。 Cron4j很好地關注它應該做什麼,有不錯的文檔,而不是廚房水槽解決方案。