我在使用 Java 调度执行器时遇到了一个奇怪的情况,我想知道我遇到的情况是否正常。
我需要安排以 5 秒的预定义速率执行的任务。预计这些任务的执行时间有时会超过 5 秒,但当运行它们的时间低于 5 秒时,备份的任务列表应快速连续运行以赶上。运行任务时,了解原始计划执行时间是很重要的(想想scheduledExecutionTime()
in java.util.TimerTask
)。最后,我需要跟踪计划时间和实际时间之间的差异,以确定时间表何时“偏离”以及偏离了多少。
到目前为止,我已经使用 Java 执行器实现了所有这些,下面的类说明了总体思路:
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 产生类似的结果)。
第二个问题是是否有一种简单的方法可以减少漂移量。如果我使用一个简单的java.util.Timer
甚至只是Thread.sleep()
,漂移是不存在的。
最后,使用计划执行器时是否有更好的方法来跟踪计划执行时间?