32

Thread.sleep()は、特定のミリ秒や特定のナノ秒のように、Java スレッドをしばらく中断させることができることを知っています。しかし問題は、この関数の呼び出しによってオーバーヘッドが発生することです。

たとえば、スレッドを 100 ナノ秒中断させたい場合、Thread.sleep(0, 100)を呼び出します。このプロセスの全コストはinvocation_cost + 100 nanosceondsであり、これは私が望むよりもはるかに大きい可能性があります。どうすればこの問題を回避し、目的を達成できますか?

これが必要な理由は、シミュレーションをオフラインで行いたいからです。タスクの実行時間をプロファイリングしました。ここで、スレッドを同じ期間中断することで、この実行時間をシミュレートしたいと考えています。

ありがとう!

4

6 に答える 6

25

スリープの粒度は、通常、スレッド スケジューラの割り込み期間によって制限されます。Linux では、最近のカーネルでは通常、この割り込み期間は 1 ミリ秒です。Windows では、スケジューラの割り込み周期は通常 10 ~ 15 ミリ秒程度です。

これよりも短い期間だけスレッドを停止する必要がある場合は、通常はビジー待機を使用します

編集: jrockit + solaris で最良の結果が得られると思います。Windows ボックスの数字はひどいものです。

@Test
public void testWait(){
    final long INTERVAL = 100;
    long start = System.nanoTime();
    long end=0;
    do{
        end = System.nanoTime();
    }while(start + INTERVAL >= end);
    System.out.println(end - start);
}
于 2012-07-16T05:40:54.370 に答える
15

シミュレーションの場合、再現可能な結果が得られないため、リアルタイムでシミュレートしようとはしません。つまり、シミュレーションをテストできません。

代わりに、データ駆動型のシミュレートされたクロックを使用して、すべてを可能な限り高速に実行します。これにより、再現可能な結果が得られ、リアルタイムよりも高速にシミュレートできます (例: 2 倍から 100 倍高速)。


スレッドの疑いがあると、約 10 マイクロ秒かかります。これより短い時間だけスレッドを中断しようとしても意味がありません。

ビジー状態で短時間待機するには、試すことができます。

long start = System.nanoTime();
while(start + delay >= System.nanoTime());

注:@ EugeneBeresovskyがコメントしているように、マシンが292年間実行された後、これはオーバーフローする可能性があるため、これを次のように書くことを選択できます

while(System.nanoTime() - start < delay);

これは、代わりに 292 年未満の遅延に対しては問題ありません。より長い遅延には System.currentTimeMillis() を使用できます。

ただし、Centos 5.x では System.nanoTime() に最大 300 ns かかるため、これを 2 回呼び出すと 100 ns よりもはるかに長くかかるため、これでも信頼できません。また、多くの OS の分解能は 1000 ns (1 マイクロ秒) しかないため、このループは、探している遅延に関係なく、最大 1 マイクロ秒まで待機します。

代わりに、最適化されていない短いループでビジー待機することができます。

100 ns の遅延の場合、別のビジー ループを作成するのではなく、待機しているものをビジー待機する方がよいと思います。

于 2012-07-16T06:49:25.597 に答える
2

ビジー待機を行います (つまり、何もしない非常に多くの数値を while ループで循環させます)。プログラムの開始時に、このビジー待機を実行するのにかかった時間を計り、それを増減して 5 ナノ秒にすることができます

私はobject.waitがこの頻度で毛むくじゃらになることを発見しましたまた、忙しい待機ソリューションはマシンに依存する可能性が最も高いことに注意してください。したがって、プログラムの開始時にキャリブレーションステップが必要な理由

于 2012-07-16T06:37:42.713 に答える
1

のもう 1 つの問題Thread.sleep()は、指定された時間後にウェイクアップすることが保証されていないことです。スリープ中のスレッドは、指定されたナノ/マイクロ秒の間スリープすることが保証されますが、その後すぐにウェイクアップすることは保証されません。あなたはナノ秒単位で話しているので、試してみてくださいObject.wait(long, int)

上記の方法では、数十ナノ秒のオーダーと完全に一致しています。

于 2012-07-16T06:36:01.767 に答える