简体   繁体   English

Java计划执行程序准确性

[英]Java scheduled executor accuracy

There is a peculiarity that I encountered while using Java scheduled executors and was wondering if what I experienced is normal. 我在使用Java计划执行程序时遇到一个奇怪的问题,并且想知道我经历的是否正常。

I need to schedule tasks that execute at a predefined rate of 5 seconds. 我需要安排以5秒的预定义速率执行的任务。 It is expected that these tasks will take longer than 5 seconds to execute from time to time, but when the time to run them goes below 5 seconds, the backed up list of tasks should run in quick succession to catch up. 预计这些任务有时会花费5秒钟以上的时间来执行,但是当它们的运行时间少于5秒钟时,备份的任务列表应该迅速连续地赶上来。 When running the tasks, it is important to know what the original scheduled execution time was (think scheduledExecutionTime() in java.util.TimerTask ). 在运行任务时,重要的是要知道原始的预定执行时间是什么(想想java.util.TimerTask scheduledExecutionTime() )。 Finally, I need to track the difference between scheduled time and actual time to identify when the schedule is "drifting" and by how much. 最后,我需要跟踪计划时间和实际时间之间的差异,以确定计划何时“漂移”以及减少多少。

So far I have implemented all of this by using Java executors, and the following class illustrates the general idea: 到目前为止,我已经使用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;
        }
    }
}

Running the code listed above shows that the drift (which ideally should be as close to 0 as possible) fluctuates by as much as a few seconds, the result of which is that tasks as executed either prematurely or late. 运行上面列出的代码表明,漂移(理想情况下应尽可能接近0)波动最多几秒钟,其结果是任务执行得过早或过晚。 I have created a graph from the results of running this for about 150 minutes: 我已经通过运行约150分钟的结果创建了一个图形:

Java执行程序漂移

So my first question is whether this is normal. 所以我的第一个问题是这是否正常。 My environment consists of 32 bit Windows XP and Java 1.5 update 21 (although Java 6 update 22 produces similar results). 我的环境由32位Windows XP和Java 1.5 update 21组成(尽管Java 6 update 22产生类似的结果)。

The second question is whether there is a simple way to reduce the amount of drift. 第二个问题是是否有一种简单的方法来减少漂移量。 If I use a simple java.util.Timer or even just Thread.sleep() , the drift is non-existent. 如果我使用简单的java.util.Timer或什至只是Thread.sleep()Thread.sleep()存在这种漂移。

Lastly, is there a better way of tracking the scheduled execution time when using scheduled executors? 最后,在使用计划执行程序时,是否有更好的方法来跟踪计划执行时间?

The scheduled executor service uses System.nanoTime which doesn't drift as much as currentTimeMillis. 计划的执行程序服务使用System.nanoTime,其漂移不如currentTimeMillis那样大。 Except if you are running on an XP system with more than one CPU socket. 除非您在具有多个CPU插槽的XP系统上运行。 There is a bug in XP where the OS call System.nanoTime() uses is not consistent between sockets so as the thread switches which socket it is running on, you can expect to see this jumping around. XP中存在一个错误,套接字之间的OS调用System.nanoTime()使用的操作系统不一致,因此线程会切换它在哪个套接字上运行,您可以期望看到这种情况不断发生。 (This is not a problem on Vista/7) (在Vista / 7上这不是问题)

On a Linux system with one socket your program reports 0 - 3 ms drift. 在具有一个套接字的Linux系统上,您的程序报告0到3毫秒的偏移。

Try this program. 试试这个程序。

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;
    }
}

On an i7 system I see approx 10 jumps of up to 2 ms. 在i7系统上,我看到大约10次跳跃,最多2 ms。 If I use the machine I see more. 如果使用机器,我会看到更多。 What I expect you might see is large negative and positive timings. 我希望您可能会看到大的负面和正面时机。

Seems normal to me, it varies in the range of 5000/2. 对我来说似乎很正常,在5000/2范围内变化。 In stead of format + println you should try a fast logging, so the overhead drift of println is not measured. 代替format + println,您应该尝试快速记录日志,因此不会测量println的开销漂移。 Would be interesting. 会很有趣。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM