2

私の友人の 1 人が彼が行ったことを見せてくれましたが、私はこれがどのように起こったのかを説明するのに深刻な途方に暮れていました.時間が経過し(その部分は Thread.sleep(1000) )、一見永遠にかかりました(10秒待っていたものが完了するまでに約3分かかりました)。どのくらいの時間が経過したかを確認するためにミリタイムを使用してみました: 毎秒経過したナノタイムの量を出力し、毎秒、ナノタイムが毎秒およそ 40 ~ 50 ミリ秒移動していることを確認しました。

System.nanotime と Java に関連するバグを確認しましたが、nanotime が突然大きく増加してから停止するというバグしか見つからなかったようです。別の質問で読んだ内容に基づいてこのブログエントリも閲覧しましたが、それを引き起こす可能性のあるものは何もありませんでした.

明らかに、代わりにミリタイムを使用するだけで、この状況を回避できます。これには多くの回避策がありますが、私が興味を持っているのは、システム クロックに関するハードウェアの問題以外に、または少なくとも CPU が持つ最も正確なクロック以外に何かがあるかどうかです (それが System.nanotime が使用しているように見えるため)。このように一貫して遅く実行される可能性がありますか?

long initialNano = System.nanoTime();
long initialMili = System.currentTimeMillis();
//Obviously the code isn't actually doing a while(true), 
//but it illustrates the point
while(true) {
    Thread.sleep(1000);
    long currentNano = System.nanoTime();
    long currentMili = System.currentTimeMillis();
    double secondsNano = ((double) (currentNano - initialNano))/1000000000D;
    double secondsMili = ((double) (currentMili - initialMili))/1000D;
    System.out.println(secondsNano);
    System.out.println(secondsMili);
}

secondsNano は 0.04 のラインに沿って何かを出力しますが、secondsMili は 1 に非常に近い値を出力します。

この行に沿ったバグがSun のバグ データベースで報告されているようですが、重複としてクローズされましたが、既存のバグへのリンクはありません。これは非常にシステム固有であるように思われるため、これがハードウェアの問題であることがますます確実になっています。

4

3 に答える 3

4

... 彼は System.nanotime を使用して、何かを実行する前にプログラムを待機させていました...

彼が何をしていたかを正確に示すコードをいくつか見せてもらえますか? 次のような奇妙な種類のビジー ループでしたか。

long t = System.nanoTime() + 1000000000L;
while (System.nanoTime() < t) { /* do nothing */ }

はいの場合、それはプログラムをしばらく一時停止させる正しい方法ではありません。Thread.sleep(...)代わりに使用して、指定されたミリ秒数だけプログラムを待機させます。

于 2009-10-14T18:02:43.407 に答える
3

使用しているループの実行に正確に 1 秒もかからないことに気付きましたか? まず、Thread.sleep() は正確であることが保証されておらず、ループ内の残りのコードの実行には時間がかかります (実際には、nanoTime() と currentTimeMillis() の両方が、基になる実装によってはかなり遅くなる可能性があります)。第 2 に、System.currentTimeMillis() も正確であるとは限りません (一部のオペレーティング システムとハードウェアの組み合わせでは 50 ミリ秒ごとにしか更新されません)。また、上記の 40 ~ 50 ミリ秒まで不正確であると述べた後、0.004 秒と言い続けますが、これは実際にはわずか 4 ミリ秒です。

System.out.println() を次のように変更することをお勧めします。

System.out.println(secondsNano - secondsMili);

このようにして、2 つのクロックが秒単位でどれだけ異なるかを確認できます。ラップトップで約 12 時間実行したままにしましたが、1.46 秒 (速く、遅くはありません) で終了しました。これは、2 つのクロックに多少のずれがあることを示しています。

currentTimeMillis() メソッドは長期間にわたってより正確な時間を提供すると思いますが、nanoTime() はより高い解像度を持ち、コードのタイミングや短い期間でミリ秒未満のタイミングを提供するのに適しています。

于 2009-11-20T23:33:26.930 に答える
1

私は同じ問題を経験しました。私の場合を除いて、それはより顕著です。

この簡単なプログラムで:

public class test {
    public static void main(String[] args) {
        while (true) {
            try { 
                Thread.sleep(1000); 
            } 
            catch (InterruptedException e) { 
            }

            OStream.out("\t" + System.currentTimeMillis() + "\t" + nanoTimeMillis());
        }
    }

    static long nanoTimeMillis() {
        return Math.round(System.nanoTime() / 1000000.0);
    }
}

次の結果が得られます。

13:05:16:380 main:  1288199116375   61530042
13:05:16:764 main:  1288199117375   61530438
13:05:17:134 main:  1288199118375   61530808
13:05:17:510 main:  1288199119375   61531183
13:05:17:886 main:  1288199120375   61531559

nanoTimeは、1秒あたり約400ミリ秒しか経過していないことを示しています。

于 2010-10-27T17:15:19.750 に答える