web-dev-qa-db-ja.com

Javaスレッドを100ナノ秒のような短い期間停止する方法は?

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

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

これが必要なのは、オフラインでシミュレーションを行いたいからです。タスクの実行時間をプロファイルしました。次に、同じ期間にスレッドを一時停止して、この実行時間をシミュレートしたいと思います。

ありがとう!

27
JackWM

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

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

[〜#〜] edit [〜#〜]:jrockit + solarisで最良の結果が得られると思います。ウィンドウボックスの数字はひどいです。

@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);
}
22
qwerty

シミュレーションでは、再現性のある結果が得られないため、リアルタイムでのシミュレーションは行いません。つまり、シミュレーションをテストすることはできません。

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


スレッドの疑いは約10マイクロ秒かかります。これよりも短い時間スレッドを一時停止しようとしても意味がありません。

ちょっと待って忙しくしてみてください。

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

注:@EugeneBeresovskyのコメントのとおり、マシンが292年間稼働した後、これがオーバーフローする可能性があるため、次のように記述することを選択できます。

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

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

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

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

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

13
Peter Lawrey
public static void busySleep(long nanos)
{
  long elapsed;
  final long startTime = System.nanoTime();
  do {
    elapsed = System.nanoTime() - startTime;
  } while (elapsed < nanos);
}
3
EntangledLoops

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

私は上記の方法で数十ナノ秒のオーダーとかなり一致しています。

1
Mohan

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

私はobject.waitがこの頻度で毛むくじゃらになっていることもわかりました。ビジーな待機ソリューションはマシンに依存する可能性が高いことに注意してください。

1
Frank Visaggio