7

私のプログラムには、スケジューラと呼ばれるコンポーネントがあり、他のコンポーネントがコールバックしたい時点を登録できます。これは、Unix cron サービスと同じように機能するはずです。つまり、スケジューラに「1 時間ごとに 10 分後に通知する」ように指示します。

Javaには実際のコールバックがないことに気づきました。

これが私のアプローチです。すでにこのようなことをしているライブラリはありますか? 改善提案もお気軽にどうぞ。

スケジューラ パスへの呼び出しを登録します。

  • 時、分、秒、年、月、dom、dow を含む時間指定。各項目は指定されていなくてもかまいません。つまり、「毎時/分などに実行する」という意味です。(crontab と同じように)
  • スケジューラによって通知されたときに呼び出し元のオブジェクトに何をすべきかを伝えるデータを含むオブジェクト。スケジューラはこのデータを処理せず、格納して通知時に戻すだけです。
  • 呼び出し元オブジェクトへの参照

起動時、または新しい登録要求の後、スケジューラは現在のシステム時刻の Calendar オブジェクトで開始し、この時点に一致するエントリがデータベースにあるかどうかを確認します。存在する場合は、それらが実行され、プロセスが最初からやり直されます。そうでない場合は、Calendar オブジェクトの時間が 1 秒増加し、内容が再チェックされます。これは、一致するエントリが 1 つ以上存在するまで繰り返されます。(離散事象シミュレーション)

スケジューラは、そのタイムスタンプ、スリープ、およびウェイクを毎秒記憶して、それが既に存在するかどうかを確認します。たまたまウェイクアップして時間が経過した場合は、時間になってジョブが実行された場合と同様に、最初からやり直します。


編集:Quartzを教えてくれてありがとう。しかし、私はもっと小さいものを探しています。

4

8 に答える 8

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クラスは完全にスタンドアロンであり、 「コンテキスト」内から呼び出されることに依存しません。次の実行時間をDateまたはとして取得したら、上記のようlongに Java を使用できますScheduledExecutorService

于 2009-03-05T11:10:46.077 に答える
4

Quartzは、この分野で大きくて明白な原動力ですが、探求すべき代替手段がいくつかあります。

Cron4jは十分にまともなライブラリであり、Quartz よりも少し軽量です。それは良いドキュメントを提供し、あなたが望むことをします。

おそらくもっと興味深いのは、Java の同時実行ライブラリ (特に Executor と ScheduledExecutor) により適したライブラリを使用したい場合、HA-JDBCにはCronThreadPoolExecutorによって実装されるCronExecutorServiceインターフェースがあります。興味深いことに、これは (CronExpression クラスを提供するために) Quartz に依存していますが、この 2 つを一緒に使用すると、Quartz 単独よりもうまく機能することがわかりました。大きな依存関係が必要ない場合は、Quartz と HA-JDBC からこれを実現する少数のクラスを簡単に抽出できます。

もっと小さいものが必要なので (編集に気づいたばかりです)、Quartz から CronExpression を取得し、上記の 2 つの HA-JDBC クラスを取得します。それでいい。

于 2009-03-05T10:58:31.583 に答える
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();
    }
  }

}

前述のように、 java.util.concurrentExecutorServiceは、必要に応じてより豊富な API を提供します。

于 2009-03-05T12:31:25.010 に答える
1

Quartz のより高度で複雑な機能がどうしても必要な場合を除き、Quartz よりもcron4j (前述)を強くお勧めします。Cron4j は本来の機能にうまく焦点を合わせており、適切なドキュメントがあり、キッチン シンクのソリューションではありません。

于 2010-04-07T06:48:54.463 に答える
0

java.util.Timerが答えとして投票されたとは信じられません。クォーツは本当にはるかに良い選択です。

java.util.Timerに対するクォーツの大きな利点は、クォーツを使用するとジョブをデータベースに保存できることです。その結果、1つのjvmがスケジュールでき、別のjvmが実行できます。また、(明らかに)要求はjvmの再起動後も存続します。

于 2009-03-07T07:54:39.743 に答える
0

おそらくもっと興味深いのは、Java の同時実行ライブラリ (特に Executor と ScheduledExecutor) により適したライブラリを使用したい場合、HA-JDBC には CronThreadPoolExecutor によって実装される CronExecutorService インターフェースがあります。興味深いことに、これは (CronExpression クラスを提供するために) Quartz に依存していますが、この 2 つを一緒に使用すると、Quartz 単独よりもうまく機能することがわかりました。大きな依存関係が必要ない場合は、Quartz と HA-JDBC からこれを実現する少数のクラスを簡単に抽出できます。

これらのクラスを抽出しようとしたところ、うまくいきました! 次の 3 つのクラスが必要でした。

  • CronExpression (クォーツ)
  • CronThreadPoolExecutor (ha-jdbc)
  • DaemonThreadFactory (ha-jdbc)

そして、これらのマイナーな調整を行うだけで済みました。

  • CronThreadPoolExecutor からロガーを削除する (作成されたが使用されなかった)
  • 定数 YEAR_TO_GIVEUP_SCHEDULING_AT を CronTrigger から CronExpression に移動しました

絡み合った依存関係のプルに引っかからなかったことに興奮しました。クラスの作成者におめでとう!

そして、それはチャンピオンのように機能しています。

于 2010-02-11T15:57:32.883 に答える