2016-03-29 16 views
0

私はWindowsシステム上で動作しているプログラムを持っています。以下のようなロジックで。私はスレッドが60秒間acutallyスリープしているが、タイムスタンプと印刷時間は55秒であることがわかります。私の知る限り、Thread.sleepとSystem.currentTimeMillisはシステム時刻に依存します。なぜ 精度とシステムタイマーとスケジューラの精度を受け、指定された期間のために(一時的に実行を停止) をスリープ状態に現在実行中のスレッドを引き起こすのThread.sleepThread.sleepとSystem.currentTimeMillis

public static void main(String[] args) throws InterruptedException { 
    logger.info("Started"); 
    long start = System.currentTimeMillis(); 

    logger.info("No Arguments passed waiting for 60 seconds...."); 
    Thread.sleep(60000); 

    logger.info("Sleep Duration: " + (System.currentTimeMillis()-start)); 
    logger.info("Ended"); 
} 
+0

私はこれを私のMACでシミュレートしようとしましたが、期待される答えを見ています。私は私のMac OSでそれをやった –

+0

もう一度それを試すことができますか?いつも「55」ですか? –

+0

必ずしも異なるとは限りません。しばらくそれは一致します。 Thread.sleepがより正確であることを理解したかっただけです。 –

答えて

1

この違いを参照ください。スレッド はモニターの所有権を失わず、実行の再開 はスケジューリングとスレッドを実行するプロセッサ の可用性によって異なります。

いずれにしても、スリープを呼び出すと指定された時間だけスレッドが一時停止されるとは限りません。

+0

でも、それは5秒で違いはありません。5ミリ秒さえも悪いと思う。ただし、Windowsのjvm implは本当に悪いですし、ウィンドウが本当に悪い場合もあります。 –

+1

通常、それは要求より少し長く眠っています。私はそれが5秒短くなっていることを決して観察しませんでした。 OPの経験は確かに奇妙です。 –

+1

@EricWang、おそらくWindows XPでは5ミリ秒が可能です... System.currentTimeMillis()の背後には非常に荒いタイマーがありました –

1

@Tagir_Valeevと言っても、あなたのウィンドウのスケジューラはそれほど良くはありません。これは私が推測する主な理由の1つです。

もう1つの理由は、2つの時点の間にlogger.info()があることです。おそらく数ミリ秒かかることがあります。

したがって、プログラムを次のように記述すると、より正確になる可能性があります。

SleepAccuracyTest.java:TestNGクラス、ロガーとしてSlf4jを使用)

import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.testng.Assert; 
import org.testng.annotations.Test; 

// test sleep accuracy, 
public class SleepAccuracyTest { 
    public static final int MAX_DIFF = 1; // max diff in milliseconds, 
    private Logger logger = LoggerFactory.getLogger(SleepAccuracyTest.class); 
    private int counter = 0; 

    @Test(invocationCount = 10, alwaysRun = true) 
    public void testIt() { 
     int during = 1000; 
     counter++; 
     try { 
      logger.info("Started [{}]", counter); 
      logger.info("No Arguments passed waiting for {} milliseconds...", during); 

      long start = System.currentTimeMillis(); 
      Thread.sleep(during); 
      long end = System.currentTimeMillis(); 

      long actualDuring = end - start; 
      long diff = actualDuring - during; 
      Assert.assertTrue(Math.abs(diff) <= MAX_DIFF); 

      logger.info("Expected during: {}, actual duration: {}, diff: {}", during, actualDuring, diff); 
      logger.info("Ended\n"); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

試験結果:私のマシン(64ビットのLinux 3.16で

、Java8、 4 cpu):

  • コードを実行すると、1〜6ミリ秒の差分があります。
  • 上記のコードを実行すると、ほとんどの場合0の差分がありますが、時には1ミリ秒の差があります(1ミリ秒は単なる丸めです)。

したがって、logger.info()またはSystem.out.printf()にも時間がかかります。 数ミリ秒に過ぎず、わずか数ミリ秒です。