Java のスケジュールされたエグゼキューターを使用しているときに遭遇した特異性があり、私が経験したことが正常であるかどうか疑問に思っていました。
定義済みの 5 秒間隔で実行されるタスクをスケジュールする必要があります。これらのタスクの実行には時々 5 秒以上かかることが予想されますが、実行時間が 5 秒未満になると、バックアップされたタスクのリストがすばやく連続して実行され、追いつく必要があります。タスクを実行するときは、最初にスケジュールされた実行時間が何であったかを知ることが重要です ( で考えscheduledExecutionTime()
てjava.util.TimerTask
ください)。最後に、予定された時間と実際の時間の差を追跡して、スケジュールがいつ、どの程度ずれているかを特定する必要があります。
これまでのところ、Java executor を使用してこれらすべてを実装してきました。次のクラスは、一般的な考え方を示しています。
public class ExecutorTest {
public static final long PERIOD = 5000;
public static void main(String[] args) {
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(
new Command(), 0, PERIOD, TimeUnit.MILLISECONDS);
}
private static final class Command implements Runnable {
long timestamp = 0;
public void run() {
long now = System.currentTimeMillis();
if (timestamp == 0) {
timestamp = now;
}
// Drift is the difference between scheduled time and execution time
long drift = now - timestamp;
String format = "Ran at %1$tF %<tT,%<tL; drift: %2$dms";
System.out.println(String.format(format, now, drift));
timestamp += PERIOD;
}
}
}
上記のコードを実行すると、ドリフト (理想的には可能な限り 0 に近づける必要があります) が数秒変動し、その結果、タスクが時期尚早または遅れて実行されることがわかります。これを約 150 分間実行した結果からグラフを作成しました。
だから私の最初の質問は、これが正常かどうかです。私の環境は、32 ビットの Windows XP と Java 1.5 update 21 で構成されています (ただし、Java 6 update 22 でも同様の結果が得られます)。
2 番目の質問は、ドリフトの量を減らす簡単な方法があるかどうかです。シンプルなjava.util.Timer
、または単にを使用するThread.sleep()
と、ドリフトは存在しません。
最後に、スケジュールされたエグゼキューターを使用するときに、スケジュールされた実行時間を追跡するより良い方法はありますか?