2012-07-16 6 views
26

私が知っているThread.sleep()は、特定のミリ秒や特定のナノ秒のようにしばらくの間、Javaスレッドを一時停止させることができます。しかし、問題は、この関数の呼び出しもオーバーヘッドを引き起こすことです。100ナノ秒のような短い時間Javaスレッドを中断する方法はありますか?

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

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

ありがとうございます!

+8

これを行う理由は何ですか?もしそうなら、それは別の方法で解決されるかもしれません... –

+0

これは珍しい要件です。あなたは[バックオフ戦略](http://en.wikipedia.org/wiki/Exponential_backoff)などが必要なようです。 – Bohemian

+1

@gt FYI、stackoverflowに関する質問を投稿するのは迷惑で、答えを提供するのではなく、あなたに質問する回答があります。何年もの間プロジェクトで発生してきたこのようなことを望んでいる多くの正当な理由があります。実用的な理由の1つは、ハードウェアからのオーディオを記録するアプリケーションでリアルタイム動作を維持することです。ハードウェアが不整合に動作する可能性があるか、テスト目的でハードウェアの動作をシミュレートすることがあります。 – EntangledLoops

答えて

17

スリープの粒度は、一般に、スレッドスケジューラの割り込み期間によって制限されます。 Linuxでは、最近のカーネルではこの割り込み期間は通常1msです。私はあなたが買ってあげる疑う:Windowsでは、スケジューラの割り込み周期は、私がこれよりも少ない期間のスレッドを停止する必要がある場合、私は通常、ビジーウェイト

EDITを使用し、通常は約10または15ミリ秒

ですjrockit + solarisでの最良の結果。窓の箱の数字はひどいです。 Thread.sleep()

@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); 
} 
+1

ありがとうございます。ビジーウェイトを使用する場合は、どのように待機時間を制御できますか? 100ナノ秒のように。 – JackWM

+1

**> = ** ** ** <= **ですか? – JackWM

+0

申し訳ありません私は間違っていました – JackWM

1

もう一つの問題は、指定した時間後にウェイクアップすることが保証されていないということです。スリープ中のスレッドは、指定されたナノ秒/マイクロ秒の間スリープ状態になりますが、その直後にウェイクアップすることはありません。あなたはナノ秒のインターミッションを話しているので、Object.wait(long, int)を試してみるとよいでしょう。

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

+2

どちらの場合でも、 'Thread.sleep()'と 'Object.wait()'を呼び出すと、現在実行中のスレッドは 'TIMED_WAITING'モードになります。これは、スレッドがCPUを解放することを意味します。どちらの場合も、待ち時間が終了すると、CPUは何か他のことをするのに忙しいでしょう。起きているスレッドが一度にCPUを受け取るという保証はなく、たとえそれがあったとしても、コンテキスト切り替え時間を支払わなければならないということです。質問によれば、これは被疑者が避けたいものです。 –

+0

さらに、 'Object.wait(timeout、nanos) 'のコードでは、' nanos> 0'の場合に 'timeout'が1だけ増加することがわかります。 – awfun

1

忙しい待ち時間をします(つまり、何もしないで何回もループしています)。あなたのプログラムの開始時間は、この忙しい待ち時間を実行し、5ナノ秒に達するまでそれを増減させるのにかかる時間を計ることができます。

私はobject.waitがこの周波数で毛むくじゃらしていることにも注意してください忙しい待っている解決策は、マシンに依存する可能性が高いです。なぜあなたは、プログラムの開始時にキャリブレーションステップを持つべきですか?

12

シミュレーションでは、再現性のある結果は得られません。つまり、シミュレーションをテストすることはできません。

代わりに、私はデータ駆動のシミュレートされたクロックを使用し、できるだけ早くすべてを実行します。これは、スレッドを疑い


は約10マイクロ秒を要し(例えば2倍に高速化するために100倍)あなたに再現可能な結果を​​与え、あなたはリアルタイムよりも速くシミュレートすることができます。これほど短時間でスレッドを一時停止しようとすることは何の意味もありません。

忙しい場合は、少し時間をお待ちください。

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

注:お使いのマシンは292年前から実行されている後@EugeneBeresovskyのコメントとして、これはあなたが

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

としてこれを書くこともできます。これは、292未満の遅延の罰金になるとオーバーフローする可能性代わりに年。 System.currentTimeMillis()を使用すると、はるかに長い遅延が得られます。

しかし、System.nanoTime()はCentos 5.xで最大300 nsかかるので、2回呼び出すと100 nsよりもはるかに長い時間がかかることになります。また、多くのOSは1000 ns(1マイクロ秒)の分解能しか持たないため、探している遅延にかかわらず、このループは1マイクロ秒まで待機します。

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

遅延が100nsの場合、別のビジーループを作成するのではなく、待っているものを待つことをお勧めします。

+0

良い投稿です。=コードを修正しました(振り返ってみると、 ">"はさらに優れています)。私は6(argh)の最小文字の編集に達するために、他のいくつかの簡単な変更を加えました。ありがとう。 –

+0

while条件に整数オーバーフローのバグがあります。たとえば、2つのnanoTime()結果の差をある絶対値と比較する必要があります。 2つの絶対的なnanoTime値を互いに比較するのではなく、@ EnntledledLoopsで指定します。 –

+0

@EugeneBeresovskyあなたのマシンが292年間稼働した後、長い値がオーバーフローします...私は私の答えを更新します。 –

2
public static void busySleep(long nanos) 
{ 
    long elapsed; 
    final long startTime = System.nanoTime(); 
    do { 
    elapsed = System.nanoTime() - startTime; 
    } while (elapsed < nanos); 
} 
関連する問題