Java Thread.sleep() в Windows 10 останавливается в состоянии ожидания S3

Есть настольное приложение, которое использует Thread.sleep() для достижения длительных (минут или часов) задержек. Это же приложение прекрасно работает с Windows XP через (по крайней мере) Windows 7. Приложение вычисляет, как далеко в будущем ему нужно что-то сделать, а затем запускает Thread.sleep(msToWait). Это работает нормально, даже если система переходит в состояние ожидания S3 во время ожидания.

Начиная с Windows 10, однако, код после Thread.sleep() не выполняется "вовремя", если машина была в S3. Похоже, что машина начинает выполнять код в "msToWait" плюс время, в течение которого машина находилась в S3 (сейчас это не на 100% точно, но вероятно).

В более ранних версиях Windows такого поведения не было; Код после Thread.sleep() ожидал нужное количество времени, независимо от состояния сна.

Тестирование проводилось на текущей JVM 1.7.

Это ошибка Windows 10? Это ошибка JVM? Есть ли обходной путь?

ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ:

Программа испытаний и процедура были разработаны. Процедура состоит в том, чтобы запустить программу, заставить машину поспать около минуты, затем разбудить машину и дождаться завершения программы.

Если эта программа запущена в Windows 10 (с отчетностью 8) с версией JVM: 25.40-b25, произойдет сбой:

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 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.");
}
}

Я понимаю, что могу попробовать различные другие методы сна, но я подумал, что, поскольку я прошел и задокументировал это, я опубликую это здесь, прежде чем пробовать другие вещи.

Дополнительная информация: Эта ошибка, кажется, также появляется в Windows 8 (но не 7 или ранее).

ДОПОЛНЕНИЕ 4/4/2019

Эта проблема видна на bugs.java.com по следующему адресу JDK-8221971.

Ответ 1

Это ожидаемое, действительное поведение. Документация очень ясна, указав:

эти времена сна не гарантируются точно, потому что они ограничены средствами, предоставляемыми базовой ОС.

и

В любом случае вы не можете предположить, что вызов sleep приостанавливает поток точно за указанный период времени.

Ответ 2

это, вероятно, ошибка в Windows 10.. даже о жизненно важных вещах, выполняемых в метро, ​​например, в меню запуска иногда не удается просыпаться из приостановленного состояния своевременно (в зависимости от того, что у вас есть брандмауэр или отключено, что неудивительно). Я бы предложил проверить состояние потока/процесса с помощью processhacker или некоторых инструментов sysinternals и попытаться найти какое-то решение. затем проверьте журналы событий Windows и т.д.

или просто сделайте что-то глупое, чтобы заменить сон семафором и сном, который запускается в командной строке.

документы очень уверены в том, что он должен просыпаться своевременно, просто чтобы вы не полагались на него как выходной таймер на некоторых datalines, играли музыку или такие, но принимая 100 раз, время немного отличается.