Java预定执行程序的准确性

时间:2011-12-07 12:54:55

标签: java scheduling executor

我在使用Java预定执行程序时遇到了一个特点,并且想知道我所经历的是否正常。

我需要安排以5秒的预定义速率执行的任务。预计这些任务将不时需要超过5秒的时间执行,但是当运行它们的时间低于5秒时,备份的任务列表应该快速连续运行以赶上。运行任务时,了解原始计划执行时间非常重要(在scheduledExecutionTime()中考虑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分钟:

Java executor drift

所以我的第一个问题是这是否正常。我的环境包括32位Windows XP和Java 1.5更新21(尽管Java 6更新22产生了类似的结果)。

第二个问题是,是否有一种简单的方法可以减少漂移量。如果我使用简单的java.util.Timer甚至只是Thread.sleep(),那么漂移就不存在了。

最后,在使用预定执行程序时,是否有更好的方法来跟踪计划执行时间?

2 个答案:

答案 0 :(得分:8)

计划的执行程序服务使用的System.nanoTime不会像currentTimeMillis那样漂移。除非您在具有多个CPU插槽的XP系统上运行。在XP中有一个错误,OS调用System.nanoTime()使用的是套接字之间不一致的,所以当线程切换它运行的套接字时,你可以期待看到这种情况。 (这在Vista / 7上不是问题)

在具有一个插槽的Linux系统上,程序报告0 - 3 ms漂移。

试试这个程序。

public static void main(String... args) throws Exception {
    long start = System.nanoTime();
    long time = start;
    while(time < start + 3e10) {
        long now = System.nanoTime();
        if (now < time || now > time + 50000) {
            System.out.println(now - time);
            now = System.nanoTime();
        }
        time = now;
    }
}

在i7系统上,我看到大约10次跳跃,最多2 ms。如果我使用机器,我会看到更多。我期望你看到的是大量的消极和积极时间。

答案 1 :(得分:0)

对我而言似乎正常,它在5000/2的范围内变化。您应该尝试快速记录,而不是格式+ println,因此不会测量println的开销漂移。会很有趣。