Windows 10上的Java Thread.sleep()在S3睡眠状态下停止

Dal*_*ale 13 java windows windows-8 windows-10 sleep-mode

有一个桌面应用程序使用Thread.sleep()来实现长(数分钟或数小时)的延迟。从Windows XP(至少)到Windows 7,该应用程序都可以正常工作。该应用程序将计算将来需要执行的操作,然后单击Thread.sleep(msToWait)。即使系统在等待期间碰巧进入了S3睡眠状态,这也可以正常工作。

但是,从Windows 10开始,如果机器位于S3中,则Thread.sleep()之后的代码不会“按时”执行。看来机器开始在“ msToWait”处加上机器进入S3的时间开始执行代码(目前尚不能百分百确定,但有可能)。

Windows的早期版本没有表现出这种现象。不管睡眠状态如何,Thread.sleep()之后的代码都会等待正确的时间。

测试是在当前的JVM 1.7上进行的。

这是Windows 10错误吗?这是JVM错误吗?有解决方法吗?

附加数据:

开发了测试程序和程序。步骤是运行程序,使机器休眠约一分钟,然后唤醒机器并等待程序完成。

如果此程序在JVM版本为25.40-b25的Windows 10(报告为8)上运行,它将失败:

C:\Users\Tester\Downloads>SleepTester.exe
Wed Apr 01 10:47:35 PDT 2015 Using default number of minutes: 5
Wed Apr 01 10:47:35 PDT 2015 You can use "SleepTester -minutes 10" to have it sleep for 10 minutes, for example.
Wed Apr 01 10:47:35 PDT 2015 JVM Version: 25.40-b25 Windows Version: Windows 8
Wed Apr 01 10:47:35 PDT 2015 The program will now wait for 5 minutes.  Expect wrap-up at Wed Apr 01 10:52:35 PDT 2015
Wed Apr 01 10:53:38 PDT 2015 The system has come through the Thread.sleep(300000).
Wed Apr 01 10:53:38 PDT 2015 This should be a low number: 63589
Wed Apr 01 10:53:38 PDT 2015 This appears to be operating incorrectly...the expected sleep time has NOT been achieved.
Wed Apr 01 10:53:38 PDT 2015 Program is ending.
Run Code Online (Sandbox Code Playgroud)

如果该进程在Windows 7上运行,则不会失败。

Wed Apr 01 17:12:18 EDT 2015 Java Runtime Version: 1.8.0_31-b13 JVM Version: 25.31-b07 Windows Version: Windows 7
Wed Apr 01 17:12:18 EDT 2015 The program will now wait for 6 minutes.  Expect wrap-up at Wed Apr 01 17:18:18 EDT 2015
Wed Apr 01 17:18:18 EDT 2015 The system has come through the Thread.sleep(360000). 
Wed Apr 01 17:18:18 EDT 2015 This should be a low number: 0
Wed Apr 01 17:18:18 EDT 2015 Program is ending.
Run Code Online (Sandbox Code Playgroud)

这是测试程序:

import java.util.Date;

public class SleepTester {

private static int mMinutes;
private static int mDefault = 5;

public static void main(String[] args) throws Exception {
    for (int iArg = 0; iArg < args.length; ++iArg) {
        if (args[iArg].equals("-minutes") && (iArg + 1) < args.length) {
            mMinutes = Integer.parseInt(args[++iArg]);
        }
    }

    if (mMinutes == 0) {
        mMinutes = mDefault;
        System.out.println(new Date() + " Using default number of minutes: " + mDefault);
        System.out.println(new Date() + " You can use \"SleepTester -minutes 10\" to have it sleep for 10 minutes, for example.");
    }

    System.out.println(new Date() + " Java Runtime Version: " + System.getProperty("java.runtime.version") + " JVM Version: " + System.getProperty("java.vm.version") + " Windows Version: " + System.getProperty("os.name"));
    long msDelay = mMinutes * 60 * 1000;
    long wakePoint = new Date().getTime() + msDelay;
    System.out.println(new Date() + " The program will now wait for " + mMinutes + " minutes.  Expect wrap-up at " + new Date(wakePoint));
    Thread.sleep(msDelay); // If the machine goes into S3 during this interval, it should not matter, as long as it's awake when it fires.
    System.out.println(new Date() + " The system has come through the Thread.sleep(" + msDelay + "). ");
    long msAccuracy = Math.abs(new Date().getTime() - wakePoint);
    System.out.println(new Date() + " This should be a low number: " + msAccuracy);
    if (msAccuracy > 1000) System.out.println(new Date() + " This appears to be operating incorrectly...the expected sleep time has NOT been achieved.");
    System.out.println(new Date() + " Program is ending.");
}
}
Run Code Online (Sandbox Code Playgroud)

我意识到我可以尝试其他各种睡眠方法,但是我认为,自从我经过并记录下来之后,我便将其张贴在这里,然后再尝试其他方法。

附加信息:Windows 8(但不是7或更早版本)中也似乎会出现此故障。

日期4/4/2019

该问题在bugs.java.com上的以下URL JDK-8221971中可见

有一些较早的错误与该错误相关。链接JDK-8146730错误的评论:

17-04-2017关于此主题的任何新闻吗?

2019年4月4日已推迟。这是一个低优先级的复杂问题,没有人主动分配给它。

And*_*ico 6

这是预期的有效行为。该文档非常明确,说明:

这些睡眠时间不保证精确,因为它们受底层操作系统提供的功能的限制。

和:

无论如何,您不能假定调用sleep将在指定的时间段内精确地挂起线程。

  • 规格说不能保证精度,因此您可能不会期望精度。一个底层操作系统恰巧提供精度这一事实并不意味着Java将来有义务永远保持这种精度。Java从未承诺过精度。 (2认同)