“コールバック&#8221 ;?のスケジュールされた実行を処理するJavaライブラリクラス
-
03-07-2019 - |
質問
私のプログラムには、スケジューラと呼ばれるコンポーネントがあります。これにより、他のコンポーネントがコールバックしたい時点を登録できます。これは、Unix cronサービスとほとんど同じように機能するはずです。 e。スケジューラに「1時間ごとに10分過ぎに通知する」と伝えます。
Javaには実際のコールバックがないことを認識しています。
これが私のアプローチです。すでにこのようなことをしているライブラリはありますか?改善も提案してください。
スケジューラパスへの呼び出しの登録:
- 時間、分、秒、年、月、dom、dowを含む時間指定。各項目は指定されない場合があります。 (crontabと同様)
- スケジューラによって通知されたときに呼び出し元オブジェクトに何をするかを伝えるデータを含むオブジェクト。スケジューラはこのデータを処理せず、単に保存して通知時にそれを返します。
- 呼び出し元オブジェクトへの参照
起動時、または新しい登録要求の後、スケジューラは現在のシステム時刻のCalendarオブジェクトで開始し、この時点に一致するエントリがデータベースにあるかどうかを確認します。存在する場合、それらが実行され、プロセスが最初からやり直されます。存在しない場合、Calendarオブジェクトの時間は1秒ずつ増加し、エントリが再チェックされます。これは、一致するエントリが1つ以上になるまで繰り返されます。 (離散イベントシミュレーション)
スケジューラはそのタイムスタンプを記憶し、毎秒スリープおよびスリープ解除して、すでに存在するかどうかを確認します。たまたま起きて、時間が経過している場合は、時間が来てジョブが実行された場合と同様に、最初からやり直します。
編集:Quartzを指定してくれてありがとう。しかし、もっと小さいものを探しています。
解決
ニーズが単純な場合は、 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();
}
}
}
注記、 ExecutorService a href = "http://java.sun.com/javase/6/docs/api/java/util/concurrent/package-frame.html" rel = "nofollow noreferrer"> java.util.concurrent 必要に応じてより豊富なAPIを提供します。
他のヒント
ルックアップクォーツ
実行したい個々の時点をオブジェクトが正確に把握している場合、 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
" context"内から呼び出されることに依存しません。次の実行時間を Date
または long
にしたら、上記のようにJava ScheduledExecutorService
を使用できます
クォーツは、この分野で大きく明白な原動力ですが、探検するいくつかの代替手段があります。
Cron4j は十分なライブラリであり、Quartzよりも少し軽量です。優れたドキュメントを提供し、必要なことを行います。
おそらくより興味深いのは、Javaの同時実行ライブラリ(特にExecutorsおよびScheduledExecutors)により適したライブラリを使用する場合、 HA-JDBC には CronExecutorService インターフェース、 CronThreadPoolExecutor 。今、興味深いことに、(CronExpressionクラスを提供するために)Quartzに依存していますが、2つを一緒に使用すると、Quartzだけで動作するよりも優れていることがわかります。大きな依存関係が必要ない場合は、QuartzおよびHA-JDBCからこれを実現する少数のクラスを簡単に抽出できます。
もっと小さなものが欲しいので(編集に気付いただけです)、QuartzのCronExpressionと、上記の2つのHA-JDBCクラスを取得します。それで終わります。
絶対に必要な場合を除き、Quartzよりも cron4j (既に言及)を強くお勧めします。 Quartzのより高度で複雑な機能の一部。 Cron4jは、本来の目的にうまく焦点を合わせており、適切なドキュメントがあり、キッチンシンクソリューションではありません。
クォーツスケジューラーが推奨されます。
java.util.Timerが答えとして投票されたとは信じられません。クォーツは本当に良い選択です。
クォーツがjava.util.Timerより優れている大きな利点は、クォーツを使用すると、ジョブをdbに保存できることです。その結果、1つのjvmがスケジュールでき、別のjvmが実行できます。また、(明らかに)リクエストはjvmの再起動後も存続します。
おそらく興味深いのは、Javaの同時実行ライブラリ(特にExecutorsおよびScheduledExecutors)により適したライブラリを使用する場合、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に移動しました
私は、依存関係のもつれに引っ張られないことに興奮しました。クラス作成者の皆さん、おめでとうございます!
そしてそれはチャンピオンのように機能しています。