13

Thread.sleep() を使用して長い (分または時間) の遅延を実現するデスクトップ アプリケーションがあります。この同じアプリケーションは、Windows XP から (少なくとも) Windows 7 まで正常に動作しています。このアプリケーションは、何かを実行する必要がある未来を計算し、Thread.sleep(msToWait) をヒットします。待機中にシステムがたまたま S3 スリープ状態になったとしても、これは正常に機能しています。

ただし、Windows 10 の時点では、マシンが S3 にある場合、Thread.sleep() の後のコードは「時間どおりに」実行されません。マシンは、「msToWait」に加えて、マシンが S3 にあった時間でコードの実行を開始するようです (現時点では 100% 確実ではありませんが、可能性は高いです)。

Windows の以前のバージョンでは、この動作は見られませんでした。Thread.sleep() の後のコードは、スリープ状態に関係なく、適切な時間待機しました。

テストは現在の JVM 1.7 で行われています。

これは Windows 10 のバグですか? これは JVM のバグですか? 回避策はありますか?

追加データ:

テストプログラムと手順が開発されました。手順は、プログラムを実行し、マシンを約 1 分間スリープさせてから、マシンを復帰させ、プログラムが終了するのを待ちます。

このプログラムが 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.");
}
}

他のさまざまな睡眠方法を試すことができることはわかっていますが、これを試して文書化したので、他のことを試す前にここに投稿すると思いました.

追加情報: この障害は、Windows 8 でも発生するようです (ただし、7 以前では発生しません)。

追加 2019 年 4 月 4 日

この問題は、bugs.java.com の次の URL [JDK-8221971][1] で確認できます。

そのバグに関連する以前のバグがいくつかあります。linke JDK-8146730 バグからのコメント:

17-04-2017 このトピックに関するニュースはありますか?

2019.04.04 延期となりました。これは優先度が低く、複雑な問題であり、誰も積極的に割り当てられていません。

追加 2021 年 2 月 17 日

これはおそらく、Windows オペレーティング システムがタイムアウトに応答するようにプログラムされている方法が変更されたためです。Windows API を直接使用しても、古い Windows OS と新しい Windows OS の動作を同じにするという目標を達成する方法がわかりません。

Windows XP、Windows Server 2003、Windows Vista、Windows 7、Windows Server 2008、および Windows Server 2008 R2: dwMilliseconds 値には、低電力状態で費やされた時間が含まれます。たとえば、コンピュータがスリープしている間、タイムアウトはカウントダウンを続けます。

Windows 8、Windows Server 2012、Windows 8.1、Windows Server 2012 R2、Windows 10、および Windows Server 2016: dwMilliseconds 値には、低電力状態で費やされた時間は含まれません。たとえば、コンピュータがスリープ状態の間、タイムアウトはカウントダウンしません。

https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitforsingleobjectex

4

2 に答える 2

6

これは予期された有効な動作です。ドキュメントは非常に明示的で、次のように述べています。

これらのスリープ時間は、基盤となる OS によって提供される機能によって制限されるため、正確であるとは限りません。

と:

いずれにせよ、呼び出しsleepによって、指定された正確な時間だけスレッドが中断されるとは限りません。

于 2015-04-01T22:16:32.317 に答える
3

それはおそらくWindows 10のバグです..メトロで行われたスタートメニューのような重要なことでさえ、タイムリーにサスペンド状態から復帰できないことがあります(ファイアウォールまたは無効にしたものすべてに応じて、驚くことではありません)。processhacker またはいくつかの sysinternals ツールを使用してスレッド/プロセスの状態を確認し、解決策を考え出すことをお勧めします。次に、Windows イベント ログなどで確認します。

または、スリープをセマフォに置き換えてコマンドラインでスリープを実行するなど、ばかげたことをしてください。

ドキュメントは、タイムリーにウェイクアップする必要があることを確信していますが、一部のデータライン、音楽の再生などの出力タイマーとして依存するべきではありませんが、100倍の時間がかかるのは少し異なります。

于 2016-07-30T19:04:35.327 に答える