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

Windows 10上的Java Thread.sleep()在S3睡眠状态下停止,java,windows,windows-8,windows-10,sleep-mode,Java,Windows,Windows 8,Windows 10,Sleep Mode,有一个桌面应用程序使用Thread.sleep()实现长时间(分钟或小时)延迟。从WindowsXP到(至少)Windows7,这个应用程序一直运行良好。应用程序计算将来需要做什么,然后点击Thread.sleep(msToWait)。即使系统在等待过程中碰巧进入S3睡眠状态,这项工作也很正常 但是,从Windows 10开始,如果机器处于S3状态,则Thread.sleep()之后的代码不会“按时”执行。机器似乎在“msToWait”加上机器在S3中的时间开始执行代码(现在不是100%确定,但

有一个桌面应用程序使用Thread.sleep()实现长时间(分钟或小时)延迟。从WindowsXP到(至少)Windows7,这个应用程序一直运行良好。应用程序计算将来需要做什么,然后点击Thread.sleep(msToWait)。即使系统在等待过程中碰巧进入S3睡眠状态,这项工作也很正常

但是,从Windows 10开始,如果机器处于S3状态,则Thread.sleep()之后的代码不会“按时”执行。机器似乎在“msToWait”加上机器在S3中的时间开始执行代码(现在不是100%确定,但很可能)

早期版本的Windows没有表现出这种行为;Thread.sleep()之后的代码等待了正确的时间,而与睡眠状态无关

已经在当前的JVM1.7上进行了测试

这是Windows10的错误吗?这是一个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.
如果进程在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.
这是测试程序:

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.");
}
}
import java.util.Date;
公共类睡眠测试仪{
私有静态整数;
私有静态int-mDefault=5;
公共静态void main(字符串[]args)引发异常{
对于(int-iArg=0;iArg1000)System.out.println(new Date()+“这似乎操作不正确…未达到预期的睡眠时间。”);
System.out.println(新日期()+“程序正在结束”);
}
}
我意识到我可以尝试各种其他的睡眠方法,但我想既然我已经完成并记录了这些,我会在尝试其他方法之前把它贴在这里

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

新增日期:2019年4月4日 该问题可在bugs.java.com上的以下url[JDK-8221971][1]上看到。 有几个早期的bug与该bug相关。来自linke JDK-8146730错误的评论:

2017年4月17日关于这个话题有什么新闻吗

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

增补日期:2021年2月17日 这可能是由于Windows操作系统编程响应超时的方式发生了变化。即使直接使用Windows API,我也不确定如何实现新旧Windows操作系统行为一致的目标

Windows XP、Windows Server 2003、Windows Vista、Windows 7、Windows Server 2008和Windows Server 2008 R2:DWM毫秒值不包括在低功耗状态下花费的时间。例如,当计算机处于睡眠状态时,超时确实会持续倒计时

Windows 8、Windows Server 2012、Windows 8.1、Windows Server 2012 R2、Windows 10和Windows Server 2016:DWM毫秒值不包括在低功耗状态下花费的时间。例如,当计算机处于睡眠状态时,超时不会一直倒计时


这是预期的、有效的行为。报告非常明确,指出:

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

以及:

在任何情况下,您都不能假设调用
sleep
将在指定的时间段内暂停线程


这可能是windows 10中的一个bug。。即使是在metro中完成的操作系统重要的事情,如开始菜单,有时也无法及时从暂停状态中唤醒(这取决于您所防火墙或禁用的内容,这并不奇怪)。我会建议使用processhacker或一些sysinternals工具检查线程/进程的状态,并尝试提出一些解决方案。然后检查windows事件日志等

或者只是做一些愚蠢的事情,比如用信号量替换sleep,然后在命令行中执行sleep


医生们非常确信它应该及时醒来,只是你不应该依赖它作为一些数据线的输出计时器,播放音乐或类似的东西,但是花100倍的时间是有点不同的。

不确定错误在哪里,但是你能试着用
TimeUnit.XXX.sleep(someQuantity)
代替它吗,或者
Thread.nanoSleep()
(前者只是后者的包装),看看它是否有区别?还有,什么JVM?我建议