22

1〜2ミリ秒以下のエラーを持つJava用のThread.sleep()を提供するライブラリを知っている人はいますか?

Sleep、エラー測定、BusyWaitを組み合わせて試しましたが、さまざまなWindowsマシンでこれを信頼できるものにはなりません。

LinuxとMacOSでも実装が利用できる場合は、ネイティブ実装にすることができます。

編集 ニックが提供したリンク(http://blogs.oracle.com/dholmes/entry/inside_the_hotspot_vm_clocks)は、Javaが持つあらゆる種類のタイマー/スリープ/時計の問題を理解するための非常に優れたリソースです。

4

9 に答える 9

18

睡眠の粒度を向上させるために、このThread.sleepページから次のことを試すことができます。

WindowsでのThread.sleep()のバグ

アプリケーションにとってタイミングが重要である場合、これらのバグを回避するためのエレガントではないが実用的な方法は、アプリケーションの期間中、デーモンスレッドを実行したままにして、単純に大きな素数ミリ秒の間スリープすることです(Long.MAX_VALUEで十分です)。このように、割り込み期間はアプリケーションの呼び出しごとに1回設定され、システムクロックへの影響を最小限に抑え、デフォルトの割り込み期間が15msでない場合でも、スリープの粒度を1msに設定します。

このページには、システム全体でWindowsが変更され、このバグが原因でユーザーの時計が速く動作する可能性があることも記載されています。

編集

これに関する詳細は 、Sunからの関連するバグレポートとここで入手できます。

于 2009-05-05T11:30:00.700 に答える
12

これは約5か月遅れますが、この質問を読んでいる人には役立つかもしれません。私はそれが(理論的には)ナノ秒の精度で、実際よりもはるかに優れた精度でjava.util.concurrent.locks.LockSupport.parkNanos()同じことをすることを発見しました。もちろん、これは使用しているJavaランタイムに依存するため、YMMVです。Thread.sleep()Thread.sleep()

ご覧ください:LockSupport.parkNanos

(これは、SunのLinux用1.6.0_16-b01 VMで確認しました)

于 2009-10-28T19:02:04.363 に答える
9

残念ながら、Java 6の時点では、Windows OSのすべてのJavaスリープ関連メソッド(LockSupport.awaitNanos()を含む)は、上記の何人かの人々が述べたように、ミリ秒に基づいています。

正確な間隔を数える1つの方法は、「スピンイールド」です。System.nanoTime()メソッドは、かなり正確な相対時間カウンターを提供します。この通話の費用はハードウェアによって異なり、2000〜50ナノ秒のどこかにあります。

Thread.sleep()の代替案を次に示します。

   public static void sleepNanos (long nanoDuration) throws InterruptedException {
        final long end = System.nanoTime() + nanoDuration;
        long timeLeft = nanoDuration;
        do {
            if (timeLeft > SLEEP_PRECISION)
                Thread.sleep (1);
            else
                if (timeLeft > SPIN_YIELD_PRECISION)
                    Thread.yield();

            timeLeft = end - System.nanoTime();
        } while (timeLeft > 0);
    }

このアプローチには1つの欠点があります。待機ヒットCPUコアの最後の2〜3ミリ秒の間です。sleep()/ yield()は他のスレッド/プロセスと共有することに注意してください。CPUの少しを妥協することをいとわないなら、これはあなたに非常に正確な睡眠を与えます。

于 2010-06-07T03:28:27.263 に答える
4

通常のコードで使用する正当な理由はありませんThread.sleep()-それは(ほとんど)常に悪い設計を示しています。最も重要なのは、スレッドが指定された時間後に実行を継続するという保証がないことです。これは、のセマンティクスが特定の時間Thread.sleep()実行を停止するだけであり、その期間が経過した直後に継続しないためです。

ですから、あなたが何を達成しようとしているのかはわかりませんが、代わりにタイマーを使用する必要があると確信しています。

于 2009-05-05T10:04:44.477 に答える
4

JDKはTimerクラスを提供します。

http://java.sun.com/j2se/1.5.0/docs/api/java/util/Timer.html

ドキュメントを読むと、これを一般化されたフレームワークにするための配管以外に、Object.wait(timeout)の呼び出しよりも洗練されたものは何も使用されていないことが明確に示されています。

http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Object.html#wait(long)

したがって、Object#waitを自分で使用するだけで、追跡を削減できる可能性があります。

これらの考慮事項を超えて、JVMはプラットフォーム間で時間の精度を保証できないという事実が残っています。( http://java.sun.com/j2se/1.5.0/docs/api/java/lang/System.html#currentTimeMillis()のドキュメントを読んでください)

プラットフォームで可能な限り最高のタイミング精度が必要な場合は、タイマーとビジーポーリングを組み合わせた妥協案を試す必要があると思います。事実上、Object#wait(1)-> System#nanoTime->デルタの計算->[必要に応じてループ]。

自分でロールすることをいとわない場合、JNIは、プラットフォーム固有のソリューションに対してほぼオープンなままにします。私は幸いにもWindowの内部に気づいていませんが、明らかにホストOSが十分に正確なリアルタイムタイマーサービスを提供している場合、timerRequest(timedelta、callback)ネイティブライブラリを設定するための最低限の構造は手の届かないものであってはなりません。

于 2009-05-05T11:15:46.147 に答える
3

Long.MAX_VALUEハックは実用的なソリューションです。

Object.wait(int milis)を試してThread.sleepを置き換えましたが、Object.waitはThread.sleep(Windowsでは10ms)と同じくらい正確であることがわかりました。ハックがなければ、どちらの方法もアニメーションには適していません

于 2009-05-15T05:10:44.183 に答える
1

現在のスレッドでThread::join オーバーライドの1つを使用します。待機するミリ秒(およびナノ秒)数を指定します。

于 2009-05-05T09:43:49.037 に答える
1

新しい同時実行ライブラリを使用してみることができます。何かのようなもの:

private static final BlockingQueue SLEEPER = new ArrayBlockingQueue(1);
public static void main(String... args) throws InterruptedException {
    for(int i=0;i<100;i++) {
        long start = System.nanoTime();
        SLEEPER.poll(2, TimeUnit.MILLISECONDS);
        long time = System.nanoTime() - start;
        System.out.printf("Sleep %5.1f%n", time/1e6);
    }
}

これは2.6〜2.8ミリ秒の間スリープします。

于 2009-05-05T19:39:26.110 に答える
0

リアルタイムJavaの実装が必要なようです。

于 2009-05-05T11:21:22.220 に答える