Java 计划执行器准确性

标签 java scheduling executor

我在使用 Java 计划执行程序时遇到了一个特殊情况,想知道我遇到的情况是否正常。

我需要安排以 5 秒的预定义速率执行的任务。预计这些任务的执行时间有时会超过 5 秒,但是当运行它们的时间低于 5 秒时,备份的任务列表应该快速连续运行以 catch 进度。运行任务时,了解最初计划的执行时间很重要(想想 java.util.TimerTask 中的 scheduledExecutionTime())。最后,我需要跟踪计划时间和实际时间之间的差异,以确定日程何时“偏离”以及偏离了多少。

到目前为止,我已经通过使用 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 update 21 组成(尽管 Java 6 update 22 产生类似的结果)。

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

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

最佳答案

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

在具有一个套接字的 Linux 系统上,您的程序报告 0 - 3 毫秒漂移。

试试这个程序。

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 毫秒的跳跃。如果我使用机器,我会看到更多。我预计您可能会看到大量的负面和正面时机。

关于Java 计划执行器准确性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8415628/

相关文章:

java - 返回以特定字母开头的单词

go - channel是否发送抢占点用于goroutine调度?

android - 多个 AsyncTasks 的串行执行

java - ThreadPoolExecutor.CallerRunsPolicy 会抛出 RejectedExecutionException 吗?

java - Java Stream中执行Reduce操作出现异常

Java 应用程序在运行我的代码后不会关闭

Java将变量传递给类返回不同的变量

Linux SCHED_OTHER (CFS) 用户时间与 SCHED_RR 和 SCHED_FIFO 用户时间

sql - 如何从批处理文件运行 .sql 文件?

caching - 在Spark Streaming中,我们可以将数据(hashmap)存储在Executor内存中吗