wait()とsleep()の違い


1204

違いは何であるwait()sleep()スレッドでは?

wait()-ingスレッドはまだ実行モードにあり、CPUサイクルを使用していますが、sleep()-ingはCPUサイクルを消費しないという理解は正しいですか?

なぜ両方が wait()ありsleep()、それらの実装は下位レベルでどのように異なるのですか?


50
非常に良い質問です。両方のセマンティクスは混同しやすいです。
Andreas Petersson、

1
とてもいい質問ですが、2つ1つです。なぜ両方が低いレベルで実装できるのと同じではないのですか(そうではありません!)私もそれに答えました。
estani 2012

スレッドAが同期ブロック内にあり、CPU内にある間、このスレッドから取得されて別のスレッドBに渡されたとします。これで、スレッドAの状態が変わり、この同期ブロックで待機している他のスレッドが内部に入ります。 ?
ピーター

1
ここではそれを説明良い記事です:qat.com/using-waitnotify-instead-thread-sleep-java
トリトンマン

3
そのEXCATLY反対は-スリープ「の使用」の利用可能なCPUサイクルのすべてが、スレッドは「WAITING」必要に応じてこれらをもたらしたことができ-stateになりますので、 -実際には、ほとんどのオペレーティングシステムで自動的にサイクルを生み出すのIFことが可能であり、したがって、スレッドは実際のCPU負荷を作成しません...ただし、古いオペレーティングシステムでは作成されます。一方、Object.wait()は、(通知されない間は)サイクルを決して使用しません。これは、JVMによって実装された、多くの場合、ソフトウェア割り込みによって実現されるためです。Thread.sleepは悪い習慣です。
specializ

回答:


838

A は、待機中のモニターをwait呼び出す別のスレッドによって「起こす」ことができますnotifyが、sleepできません。また、wait(およびnotify)はsynchronized、モニターオブジェクトのブロックで発生する必要がありますが、発生sleepしません。

Object mon = ...;
synchronized (mon) {
    mon.wait();
} 

この時点で、現在実行中のスレッドは待機し、モニターを解放します。別のスレッドが行う可能性があります

synchronized (mon) { mon.notify(); }

(同じに monオブジェクト上で)最初のスレッド(モニターで待機している唯一のスレッドであると想定)が起動します。

notifyAllモニターで複数のスレッドが待機している場合も呼び出すことができます。これにより、すべてのスレッドが起動します。ただし、モニターを取得できるスレッドは1つだけです(これwaitは、synchronizedブロックことに注意)、続行できます。残り、モニターのロックを取得できるまでブロックされます。

もう一つのポイントは、あなたが呼び出すことであるwaitObject呼び出すのに対し(つまり、あなたがオブジェクトのモニターで待つこと)自体sleepThread

さらに別のポイントは、あなたが得ることができるということであるスプリアスウェイクアップからwait(明らかな理由もなく履歴書を待っている、すなわちスレッドを)。次のように常にwait何らかの条件で回転している必要あります。

synchronized {
    while (!condition) { mon.wait(); }
}

131
いいえ、できません。中断することができます。
PeterŠtibraný2009年

9
中断するときは、中断するスレッドを知っている必要があります。notifyを呼び出すときは、オブジェクトが必要であり、このオブジェクトで「待機」している他のスレッドが存在するかどうかは気にしません。wait / notifyは通信に使用され、sleepはehm、sleepに使用されます。
PeterŠtibraný2009年

28
@オタク-なぜ世界でwait()がCPUサイクルを浪費すると言うのですか?
ロバート・ムンテアヌ

25
割り込みは、スレッドが完全に実行を停止し、残りの操作をキャンセルすることを穏やかに促すメカニズムとして意図されています。 wait/ notifyは通常、他のスレッドがタスクを完了するのを待つか、特定の条件が満たされるまで待つために使用されます。
Louis Wasserman、2007

13
私はすべての回答を読みましたが、それでもまだ情報が不足しているように感じます。多くの人がJavadocの定義と2つの英語の単語の意味を書き留めましたが、なぜ待機ではなくスリープを使用する必要があるのか​​わかりません。2つの間のベンチマークと速度の違いは何ですか?睡眠でできることをすべてできるなら、なぜ睡眠を選ばなければならないのですか?
Balazs Zsoldos 2012

334

まだ言及されていない主な違いの1つは、スレッドのスリープ中はスレッドが保持しているロックを解放しませが、待機中wait()は呼び出されたオブジェクトのロックを解放します。

synchronized(LOCK) {
    Thread.sleep(1000); // LOCK is held
}


synchronized(LOCK) {
    LOCK.wait(); // LOCK is not held
}

105
待機は、wait()を呼び出したオブジェクトのロックを解放するだけです。他のロックは解放されません。
Jon Skeet、

16
実際にはロック内からスリープを呼び出す必要はありません。ロックと待機/通知は連動していますが、ロックとスリープは無関係です。
oxbow_lakes 2009年

7
@oxbow_lakes-ロックでスリープしないでください。そのためのユースケースはほとんどありません。違いを指摘したかっただけです。
ロバート・ムンテアヌ

5
@RobertMunteanu、あなたの答えは誤解を招くようにJavaロックをsleep保持していると主張していますが、そうではありません。公平に比較​​するために、と比較すると、両方の命令でが解放されないことがわかります。違いがある場合、それは明示的にJavaロックを使用していないと言えますが、問題は「実装の下位レベルでの変化はどのようにあるのか」ということです。引用しない。synchronized(OUTER_LOCK){ Thread.sleep(1000); }synchronized(OUTER_LOCK){ synchronized(LOCK){LOCK.wait();} }OUTER_LOCKsleep
Pacerier 2014

2
@Pacerier wait()は、それが呼び出される最も内側のロックの状態に関連付けられており、コード例でwait()は、解放のみが可能で、解放はできLOCKませんOUTER_LOCK。とにかく、Javaモニターはこのように設計されています。公正な比較はとにsynchronized(OUTER_LOCK){ synchronized(LOCK) { Thread.sleep(1000); } }なりsynchronized(OUTER_LOCK){ synchronized(LOCK) { LOCK.wait(); } }ます。この場合sleep()、両方のロックが保持wait()されますLOCKが、解放されますが保持されますOUTER_LOCK
danze '19年

244

私が見つかりました。この記事は役に立ちます。それは違いますThread.sleep()Thread.yield()と、Object.wait()人間の言葉では。引用するには:

最終的には、タイムスライスをプロセスとスレッドに渡すOSのスケジューラにまで到達します。

sleep(n) 言う 「私は自分のタイムスライスで終わりだ、と私に少なくともnミリ秒のために別のものを与えないでください。」OSは、要求された時間が経過するまで、スリープ状態のスレッドをスケジュールすることすらしません。

yield() 言う 「私は私のタイムスライスで終わりだが、私はまだやるべき仕事を持っています。」OSは、スレッドに別のタイムスライスをすぐに与えたり、他のスレッドを与えたり、CPUを処理したりするスレッドを放棄したりできます。

wait()言う私は私のタイムスライスで終わりです」。誰かがnotify()を呼び出すまで、別のタイムスライスを与えないでください。」と同様sleep()に、OSは、誰かが呼び出さない限りnotify()(または他のいくつかのウェイクアップシナリオの1つが発生した場合)、タスクのスケジュールを設定しません。

スレッドは、ブロッキングIOを実行するとき、および他のいくつかの状況下で、残りのタイムスライスも失います。スレッドがタイムスライス全体で機能する場合、OSは大まかに強制的に制御を取得します。yield()呼び出さ他のプロセスが実行できるようにします。

必要yield()になることはめったにありませんが、論理的なタスク境界を備えたコンピューティング負荷の高いアプリがある場合、挿入することでシステムの応答yield() 性が向上する可能性があります(時間を犠牲にして、OSだけでなくOSへのコンテキスト切り替えも無料ではありません)。いつものように、気になる目標を測定してテストします。


Yieldは基本的にプラットフォームに依存しています... javamex.com/tutorials/threads/yield.shtml
Pacerier

の説明でsleep(n)は、現在実行中のスレッドがロックのモニターを自発的に放棄していると暗黙的に述べられていますが、これは正しくありませんスレッドのjavadocからの引用:「スレッドはモニターの所有権を失うことはありません。」
クリントイーストウッド

2
@Jonathanは回答にモニターについて言及しsleepていません。これは、他のJavaメソッド呼び出しよりもモニターに関して特別な動作がないためです。つまり、どのような方法でもモニターと対話したり変更したりすることはありません。モニターについて何か言う場合waitは、上記の内容に加えて、呼び出されたオブジェクトのロックを一時的に放棄することを指定する必要があります。
pqnet 2015

通知はOSスケジューラレベルでどのように機能しますか?notifyは、特定のスレッドIDである種のイベントハンドラーを呼び出し、スケジューラーが関連するスレッドを実行中のキューに戻すことを可能にしますか?また、別の質問があります。スピンロックの概念はどこに適合しますか?それは睡眠にのみ関連するのでしょうか、それとも待機自体は非常に低いレベルでスピンロックを使用しますか?
CMCDragonkai 2015

@Erich、wait(n)と比較するために使用しsleep(n)ます。引数なしのものを使用して比較しても意味がありません。
ペーチェリエ

68

ここには多くの答えがありますが、言及されている意味上の違いは見つかりませんでした。

それはスレッド自体に関するものではありません。非常に異なるユースケースをサポートするため、両方の方法が必要です。

sleep()以前と同じようにスレッドをスリープ状態に送信し、コンテキストをパックして、事前定義された時間だけ実行を停止します。したがって、期限内にそれを起こすためには、スレッド参照を知る必要があります。これは、マルチスレッド環境では一般的な状況ではありません。これは主に、時刻同期(たとえば、正確に3.5秒でスリープ解除)および/またはハードコードされた公平性(しばらくスリープして、他のスレッドを機能させる)に使用されます。

wait()逆に、はスレッド(またはメッセージ)の同期メカニズムであり、参照を保存していない(注意していない)スレッドに通知できます。これは、パブリッシュ/サブスクライブパターン(wait==サブスクライブおよびnotify()==パブリッシュ)と考えることができます。基本的にnotify()を使用すると、メッセージを送信します(まったく受信されないこともあり、通常は気にしません)。

要約すると、通常sleep()は時刻同期とwait()マルチスレッド同期に使用します。

それらは、基盤となるOSで同じ方法で実装することも、まったく実装しないこともできます(以前のバージョンのJavaには実際のマルチスレッドがなかったため、おそらく一部の小さなVMではそれもできません)。JavaがVM上で実行されることを忘れないでください。そのため、コードは、Javaが実行されるVM / OS / HWに応じて異なるものに変換されます。


54

ここでは、wait()sleep()メソッドのいくつかの重要な違いを示しました。
PS: また、リンクをクリックしてライブラリコードを確認してください(内部での作業、理解を深めるために少し遊んでみてください)。

待つ()

  1. wait() メソッドはロックを解放します。
  2. wait()Objectクラスのメソッドです。
  3. wait() 非静的な方法です- public final void wait() throws InterruptedException { //...}
  4. wait()notify()またはnotifyAll()メソッドによって通知される必要があります。
  5. wait() メソッドは、誤警報を処理するためにループから呼び出される必要があります。

  6. wait() メソッドは、同期されたコンテキスト(つまり、同期されたメソッドまたはブロック)から呼び出す必要があります。それ以外の場合はスローされます IllegalMonitorStateException

睡眠()

  1. sleep() メソッドはロックを解放しません。
  2. sleep()java.lang.Threadクラスのメソッドです。
  3. sleep() 静的メソッドです- public static void sleep(long millis, int nanos) throws InterruptedException { //... }
  4. 指定された時間の後、 sleep()完了します。
  5. sleep()ループから呼び出さない方がよい(つまり、以下のコードを参照)。
  6. sleep()どこからでも呼び出すことができます。特定の要件はありません。

参照:待機とスリープの違い

待機およびスリープメソッドを呼び出すためのコードスニペット

synchronized(monitor){
    while(condition == true){ 
        monitor.wait()  //releases monitor lock
    }

    Thread.sleep(100); //puts current thread on Sleep    
}

thread transition to different thread states


notify()の呼び出しによってスリープ状態のスレッドが起こされるのは正しいことですか?ここにある他の投稿のいくつかは、スリープ状態のスレッドは起こされないが中断されることを暗示しているようです。
berimbolo 2017

はい、Thread.sleep()プロセッサ時間を他のスレッドで利用できるようにするために使用されます。スリープ期間は、割り込みによって(つまり、JVMによって)終了できます。このstackoverflow.com/questions/4264355/…
roottraveller 2017

その投稿はまた、interrupt()がスリープ状態のスレッドを起こすものだと言っていますか?あなたが投稿したスレッドの状態図で、notifyまたはnotifyAllがスリープ状態の(待機していない)スレッドを実行の準備に戻すと言っていました。私はそれを確実に理解したいだけです。
ビリンボロ2017

@berimbolo notify()またはnotifyAll()あるObjectクラスのメソッド。したがって、これらはすべてのクラスのオブジェクト(つまり、ここではThreadクラスも含む)で使用できます。コードの参照grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/...
roottraveller

2
OKスレッドスケジューリングの詳細を読む必要があります。これは、notify()またはnotifyAll()がスリープ状態のスレッドをウェイクアップして、interrupt()がこれを実行している例を見つけることができないためです。すべての例は、notify()およびnotifyAll()を、いくつかのモニターオブジェクトで待機しているスレッドに関連付けています。
ビリンボロ2017

29

待機とスリープに取り組んだ後に結論するいくつかの主な違いはあります。まず、wait()とsleep()を使用してサンプルを見てください。

例1待機()およびスリープ()の使用:

synchronized(HandObject) {
    while(isHandFree() == false) {
        /* Hand is still busy on happy coding or something else, please wait */
        HandObject.wait();
    }
}

/* Get lock ^^, It is my turn, take a cup beer now */
while (beerIsAvailable() == false) {
    /* Beer is still coming, not available, Hand still hold glass to get beer,
       don't release hand to perform other task */
    Thread.sleep(5000);
}

/* Enjoy my beer now ^^ */
drinkBeers();

/* I have drink enough, now hand can continue with other task: continue coding */
setHandFreeState(true);
synchronized(HandObject) {
    HandObject.notifyAll();
}

いくつかのキーノートを明確にしましょう:

  1. 呼びかける
    • wait():HandObjectオブジェクトを保持する現在のスレッドを呼び出す
    • sleep():スレッド実行時にタスクを取得してビールを取得(クラスメソッドなので現在実行中のスレッドに影響)
  2. 同期済み
    • wait():同期されたマルチスレッドが同じオブジェクト(HandObject)にアクセスする場合(複数のスレッド間の通信が必要な場合(スレッド実行コーディング、スレッド実行取得ビール)同じオブジェクトHandObjectへのアクセス)
    • sleep():実行を継続するための条件を待機しているとき(ビールを待機しています)
  3. ロックを保持する
    • wait():他のオブジェクトのロックを解放して実行する機会があります(HandObjectはフリーです。他のジョブを実行できます)
    • sleep():少なくともt回(または割り込みが発生するまで)ロックを保持します(私のジョブはまだ完了していません。ロックを保持し続け、何らかの条件が続くのを待機しています)
  4. ウェイクアップ状態
    • wait():オブジェクトからnotify()、notifyAll()を呼び出すまで
    • sleep():少なくとも期限が切れるまで、または割り込みを呼び出すまで
  5. そして最後のポイントは、エスタニが示すように使用されます:

通常、時間の同期にはsleep()を使用し、マルチスレッドの同期にはwait()を使用します。

私が間違っている場合は修正してください。


26

wait()とsleep()の違い

  • 根本的な違いは、あるwait()からであるObjectsleep()の静的メソッドですThread

  • 主な違いは、待機中にロックが解放されずwait()、ロックsleep()が解放されないことです。

  • wait()スレッド間の通信にsleep()使用されますが、一般的には、実行の一時停止を導入するために使用されます。

  • wait()同期の内部から呼び出す必要があります。そうしないとを取得IllegalMonitorStateExceptionsleep() ますが、どこからでも呼び出すことができます。

  • からスレッドを再開するにはwait()notify()またはを呼び出す必要がありnotifyAll()ます。sleep(),スレッドに関しては、指定された時間間隔の後に開始されます。

類似点

  • どちらも現在のスレッドをNot Runnable状態にします。
  • どちらもネイティブメソッドです。

18

これは非常に単純な質問です。これらの方法は両方ともまったく異なる使い方をしているためです。

主な違いは、スリープ中にロックまたはモニターが解放されるのを待たずに待機することです。待機はスレッド間の通信に使用され、スリープは実行の一時停止を導入するために使用されます。

これは明確で基本的な説明にすぎません。それ以上の情報が必要な場合は、読み続けてください。

以下の場合はwait()、メソッドスレッド待ち状態になり、私たちが呼ぶまでは、自動的に戻ってこないだろうnotify()方法を(またはnotifyAll()あなたが待機状態にもっとしてスレッドを1つ持っていて、それらのスレッドの全てを覚ますしたい場合)。また、wait()またはnotify()またはnotifyAll()メソッドにアクセスするには、同期ロック、オブジェクトロック、またはクラスロックが必要です。そしてもう1つ、このwait()メソッドはスレッド間通信に使用されます。これは、スレッドが待機状態になった場合、別のスレッドがそのスレッドをウェイクアップする必要があるためです。

しかし、sleep()この場合、プロセスを数秒間または必要な時間だけ保持するために使用される方法です。スレッドを取り戻すために、メソッドnotify()notifyAll()メソッドを呼び出す必要がないからです。または、そのスレッドをコールバックするために他のスレッドを必要としません。たとえば、ユーザーの番後のゲームのように、数秒後に何かが発生したい場合は、コンピューターが再生されるまでユーザーに待機させたい場合は、sleep()メソッドに言及できます。

インタビューでよく聞かれるもう1つの重要な違いsleep()は、Threadクラスにwait()属していることとObjectクラスに属していることです。

これらは、間のすべての違いですsleep()wait()

また、両方のメソッドには類似点があります。どちらもチェックされたステートメントであるため、これらのメソッドにアクセスするにはキャッチまたはスローを試す必要があります。

これがお役に立てば幸いです。


16

ソース:http : //www.jguru.com/faq/view.jsp?EID=47127

Thread.sleep()現在のスレッドをしばらくの間「実行不可」状態にします。スレッドは、取得したモニターを保持します。つまり、スレッドが現在同期ブロックまたはメソッド内にある場合、他のスレッドはこのブロックまたはメソッドに入ることはできません。別のスレッドが呼び出すt.interrupt()と、スリープ状態のスレッドが起動します。

sleepは静的メソッドであることに注意してください。つまり、現在のスレッド(sleepメソッドを実行しているスレッド)に常に影響します。よくある間違いはt.sleep()、tが別のスレッドである場合に呼び出すことです。それでも、スリープするのは現在のスレッドであり、tスレッドではありません。

t.suspend()廃止予定です。これを使用すると、現在のスレッド以外のスレッドを停止することができます。中断されたスレッドはすべてのモニターを保持し、この状態は中断できないため、デッドロックが発生しやすくなります。

object.wait()のように現在のスレッドを「実行不可」状態にsleep()しますが、ひねりを加えています。スレッドではなくオブジェクトで待機が呼び出されます。このオブジェクトを「ロックオブジェクト」と呼びます。lock.wait()が呼び出される前に、現在のスレッドはロックオブジェクトで同期する必要があります。wait() 次に、このロックを解放し、ロックに関連付けられている「待機リスト」にスレッドを追加します。その後、別のスレッドが同じロックオブジェクトで同期してを呼び出すことができますlock.notify()。これにより、元の待機中のスレッドが起動します。基本的に、wait()/ notify()sleep()/ interrupt()に似 ています。アクティブなスレッドのみが、スリープ状態のスレッドへの直接ポインタを必要とせず、共有ロックオブジェクトへのポインタのみを必要とします。


14

待機とスリープは2つの異なるものです。

  • ではsleep()、スレッド指定された期間のために働いて停止します。
  • ではwait()、オブジェクトビーイングが待っていた-になるまで、一般的に他のスレッドによって、通知されたスレッド動作を停止します。

ただし、スリープ中のスレッドを中断できます。その場合、wait()は冗長であり、CPUサイクルも浪費します:-(
Geek

9
待機はCPUサイクルを無駄にしません。
PeterŠtibraný2009年

1
@ピーター-そうだと思います。CPUサイクルのチャンクを待機してから、OSは他のスレッドにCPUサイクルを割り当てます。これはOSに依存していると思いますが、よくわかりません。
オタク

3
CPUサイクルを浪費する場合、wait()の実装は非常に貧弱になります。スレッド間通信では、待機/通知がかなり使用されます。
PeterŠtibraný2009年

2
@Pacerier 2つのコンストラクトは異なる目的で使用されます。使用するスレッドを一定時間sleep停止させたい場合、wait/ から他の入力が送られるまでスレッドを停止させたい場合notifyinterruptスレッドの実行を停止して終了するようにスレッドに通知する方法として意図されています。これはによって処理されますがsleepwaitI / O関数もブロックされます(メソッドを呼び出すことにより、同じ動作の関数を実装できますThread.interrupted())。パフォーマンスに関しては、機能は通常、設計された目標に合わせて最適化されています。
pqnet 2015

11

sleep の方法です Threadwait方法であるObjectので、wait/notify(使用してJava内の共有データを同期させる技術であるモニタ)が、sleepそれ自体を一時停止するためのスレッドの簡単な方法です。


8

睡眠()は、数秒間または必要な時間プロセスを保持するために使用されるメソッドですが、wait()メソッドの場合、スレッドは待機状態になり、notify()を呼び出すまで自動的に復帰しません。 notifyAll()。

な違いは、wait()がロックまたはモニターを解放する一方で、sleep()は待機中にロックまたはモニターを解放しないことです。待機はスレッド間の通信に使用され、スリープは通常、実行の一時停止を導入するために使用されます。

Thread.sleep()は、現在のスレッドをしばらくの間「実行不可」状態にします。スレッドは取得したモニターを保持します。つまり、スレッドが現在同期ブロックまたはメソッド内にある場合、他のスレッドはこのブロックまたはメソッドに入ることはできません。別のスレッドがt.interrupt()を呼び出すと、スリープ状態のスレッドが起動します。sleepは静的メソッドであることに注意してください。つまり、現在のスレッド(sleepメソッドを実行しているスレッド)に常に影響します。よくある間違いは、tが別のスレッドであるt.sleep()を呼び出すことです。それでも、スリープするのは現在のスレッドであり、tスレッドではありません。

object.wait()は、sleep()のように現在のスレッドを「実行不可」状態にしますが、ひねりを加えています。スレッドではなくオブジェクトで待機が呼び出されます。このオブジェクトを「ロックオブジェクト」と呼びます。lock.wait()が呼び出される前に、現在のスレッドはロックオブジェクトで同期する必要があります。次に、wait()はこのロックを解放し、ロックに関連付けられた「待機リスト」にスレッドを追加します。その後、別のスレッドが同じロックオブジェクトで同期し、lock.notify()を呼び出すことができます。これにより、元の待機中のスレッドが起動します。基本的に、wait()/ notify()はsleep()/ interrupt()に似ています。アクティブなスレッドのみが、スリープ中のスレッドへの直接のポインタを必要とせず、共有ロックオブジェクトへのポインタのみを必要とします。

synchronized(LOCK) {   
   Thread.sleep(1000); // LOCK is held
}

synchronized(LOCK) {   
   LOCK.wait(); // LOCK is not held
}

上記のすべてのポイントを分類してみましょう:

Call on:

  • wait():オブジェクトを呼び出します。現在のスレッドはロックオブジェクトで同期する必要があります。
  • sleep():スレッドを呼び出します。常に現在実行中のスレッド。

Synchronized:

  • wait():同期されると、複数のスレッドが同じオブジェクトに1つずつアクセスします。
  • sleep():同期すると、複数のスレッドがスリープ状態のスレッドのスリープ状態を待ちます。

Hold lock:

  • wait():他のオブジェクトが実行できるようにロックを解放します。
  • sleep():タイムアウトが指定された場合、または誰かが割り込んだ場合、少なくともt回はロックを保持します。

Wake-up condition:

  • wait():オブジェクトからnotify()、notifyAll()を呼び出すまで
  • sleep():少なくとも期限切れになるか、interrupt()を呼び出すまで。

Usage:

  • sleep():時間同期および
  • wait():マルチスレッド同期用。

参照:diff sleepおよびwait


6

簡単に言えば、待機は他のスレッドがあなたを呼び出すまで待機するのに対し、スリープは指定された期間、「次のステートメントを実行しない」です。

さらに、sleepはThreadクラスの静的メソッドであり、スレッドで動作しますが、wait()はObjectクラスであり、オブジェクトで呼び出されます。

別のポイントとして、いくつかのオブジェクトでwaitを呼び出すと、関連するスレッドがオブジェクトを同期してから待機します。:)


1
なぜ両方が必要なのですか?なぜsleep()では不十分ですか?
オタク

2
通知は、スレッド間の通信に使用されます。waitを呼び出すには、いくつかのオブジェクトが必要であり、それを同期してから、wait onを呼び出します。通知を受けるには、同じオブジェクトで同期する他のスレッドが必要で、notifyを呼び出します。
PeterŠtibraný2009年

6

waitそしてsleep方法は非常に異なります:

  • sleep 「目覚める」方法はありません、
  • 一方wait、別のスレッドがnotifyまたはを呼び出して、待機期間中に「ウェイクアップ」する方法がありnotifyAllます。

考えてみると、名前はその点で混乱しています。ただしsleep、標準的な名前であり、Win API やのwaitようなものです。WaitForSingleObjectWaitForMultipleObjects


3
しかし、睡眠を中断できるのではないでしょうか。それで、そのスリープ/割り込みと待機/通知の違いは何ですか?
Pacerier

2
眠っている人を遮ることはできますが、通知できるのは待っている人だけです。スレッドは同じです。
Rishi

5

この投稿から:http : //javaconceptoftheday.com/difference-between-wait-and-sleep-methods-in-java/

wait()メソッド。

1)wait()メソッドを呼び出すスレッドは、保持しているロックを解放します。

2)他のスレッドが同じロックでnotify()またはnotifyAll()メソッドを呼び出した後、スレッドはロックを取り戻します。

3)wait()メソッドは、同期されたブロック内で呼び出す必要があります。

4)wait()メソッドは常にオブジェクトで呼び出されます。

5)待機中のスレッドは、notify()またはnotifyAll()メソッドを呼び出すことにより、他のスレッドによって起こされることができます。

6)wait()メソッドを呼び出すには、スレッドにオブジェクトロックが必要です。

sleep()メソッド

1)sleep()メソッドを呼び出すスレッドは、保持しているロックを解放しません。

2)sleep()メソッドは同期ブロック内または同期ブロック外で呼び出すことができます。

3)sleep()メソッドは常にスレッドで呼び出されます。

4)スリープ状態のスレッドは、他のスレッドによって起こされることはありません。その場合、スレッドはInterruptedExceptionをスローします。

5)sleep()メソッドを呼び出すために、スレッドはオブジェクトをロックする必要はありません。


4

ここで、wait()は別のスレッドによって通知されるまで待機状態になりますが、sleep()にはしばらく時間がかかります。その後、自動的にReady状態に移行します...


4
  1. wait()Objectクラスのメソッドです。クラスの
    sleep()メソッドですThread

  2. sleep()スレッドがsleepxミリ秒間状態になることを許可します。
    スレッドがスリープ状態になるときit doesn’t release the lock

  3. wait()スレッドがロックを解放できるようにしますgoes to suspended state
    このスレッドは、同じオブジェクトに対してnotify()またはnotifAll()メソッドが呼び出されるとアクティブになります。


4

スリープ/割り込みと待機/通知の大きな違いの1つは、

不要なときに例外を生成するのは非効率的です。スレッドが互いに高速で通信している場合、割り込みを常に呼び出していると、多くの例外が発生します。これは、CPUの浪費です。


+1、実際には有効なポイントですが、実装の内部について議論する方がパフォーマンス分析に関連している可能性があります...
Pacerier

言い換えると、例外を作成するオーバーヘッドは、システムによる一方の実装と他方の実装のオーバーヘッドよりも大幅に小さくなる可能性があります。
Pacerier

3

あなたが正しい-Sleep()はそのスレッドを「スリープ」させ、CPUがオフになり、他のスレッド(コンテキストスイッチングとも呼ばれます)を処理します。

CPUを使用していないときに他の人にCPUを使用させるのは理にかなっているように見えるかもしれませんが、実際には、コンテキストの切り替えにオーバーヘッドが発生します。スレッドを切り替えるよりも、数ミリ秒間スレッドが何もしないようにするだけです。

また、スリープはコンテキストの切り替えを強制することに注意してください。

また、一般に、コンテキストの切り替えを制御することはできません。待機中に、OSは他のスレッドを処理することを選択できます(待機時間が長くなると)。


4
wait()は、現在のスレッドを処理しているCPUを保持しません。それは、コンテキストの切り替えも引き起こすという点で、スリープのようなものです:javamex.com/tutorials/threads/context_switch.shtml。私はすべてのスタックオーバーフローについて半年間尋ねてきましたが、待機/通知とスリープ/割り込みの違いが何であるか誰も知らないようです。
パセリエ2012

スリープは現在のスレッドの処理でCPUを維持しませんが、CPUがスリープを終了する瞬間を追跡する必要があるため、いずれにせよ、CPUに少し負担がかかると思います。待機中の「通知」のような外部トリガーはありません。番号?
Vladimir Nabokov

@VladimirNabokov、外部トリガーはinterruptです。終了時刻はnですwait(n)。¶¶もう8年になりますが、まだ誰も答えを出していません。
パセリエ

3

メソッドはさまざまな目的で使用されます。

Thread.sleep(5000);   // Wait until the time has passed.

Object.wait();        // Wait until some other thread tells me to wake up.

Thread.sleep(n)中断できますが、Object.wait()に通知する必要あります。待機する最大時間を指定するObject.wait(5000)ことは可能です。そのためwait、to、er を使用することは可能sleepですが、ロックに煩わされる必要があります。

どちらの方法も、スリープ/待機中にCPUを使用しません。

これらのメソッドは、ネイティブコードを使用して実装されますが、同様の構成を使用しますが、同じ方法ではありません。

あなた自身を探してください:ネイティブメソッドのソースコードは利用できますか?ファイル/src/share/vm/prims/jvm.cppが出発点です...


Thread.sleepタイミングも無期限に設定できます。Object.waitのタイミングを確定に設定することもできます。この答えは、同じことをする2つのハンマーが必要な理由を説明していません。
Pacerier 2014

Thread.sleep(big_num) 中断する必要あります。通知Object.wait(small_num) することできます。
ペーチェリエ

3

Wait()とsleep()の違いは?

Thread.sleep()作業が完了すると、そのロックのみが全員に解放されます。それが誰にもロックを解放しないまで。

  Sleep() take the key, its never release the key to anyone, when its work completed then only its release then only take the key waiting stage threads.

Object.wait()待機段階に入ると、キーが解放され、パラメータに基づいて数秒間待機します。

例えば:

あなたはあなたの右手でコーヒーを飲んでいます、あなたはあなたのプットダウンがここで同じタイプの別のオブジェクトしか取らないとき、あなたは同じ手の別の誰でも取ることができます。また。これはsleep()ですあなたは何もしなかった時間を眠っています、あなたは眠っているだけです...ここでも同じです。

待つ()。あなたが落ち込んで、あなたが待っている間に別の意味をとるとき、それは待っています

あなたはプレーヤーと同じシステムで何かを再生しています。一度に複数を再生することはできません。これは、待機して、待機と呼ばれている別の誰かの映画または歌を閉じて選択したときのことです。


3

waitロックを解放し、解放しsleepません。待機状態のスレッドは、notifyまたはnotifyAll呼び出されるとすぐに起動することができます。ただしsleep、スレッドがロックを保持している場合は、スリープ時間が経過した後でのみ適格になります。


したがって、スレッドが10秒間スリープしていて、中断された例外が発生した場合は????
オタク

@Geek An InterruptedExceptionは、Javadocで言うようにスローされます。
ローンの侯爵

@EJP:あなたはsun.java.comフォーラムにいたのと同じEJPですか?少なくともあなたのスコアは同じことを示唆しています:-)
Geek

2

sleep()メソッドは、現在のスレッドを指定された時間の間、実行状態からブロック状態に移行させます。現在のスレッドがオブジェクトのロックを保持している場合、そのスレッドはそれを保持し続けます。つまり、他のスレッドはそのクラスオブジェクトの同期メソッドを実行できません。

wait() メソッドは、現在のスレッドを指定された時間または通知までブロック状態にしますが、この場合、スレッドはオブジェクトのロックを解放します(つまり、他のスレッドが呼び出し側オブジェクトの同期メソッドを実行できます。


2

私の意見では、両方のメカニズムの主な違いは、スリープ/割り込みがスレッドを処理する最も基本的な方法であるのに対し、待機/通知はスレッドの相互通信を容易にすることを目的とした抽象化です。これは、スリープ/割り込みが何でもできることを意味しますが、この特定のタスクは実行するのがより困難です。

待機/通知の方が適しているのはなぜですか?ここにいくつかの個人的な考慮事項があります:

  1. 集中化を実施します。単一の共有オブジェクトを使用して、スレッドのグループ間の通信を調整できます。これにより、作業が大幅に簡略化されます。

  2. 同期を実行します。プログラマが待機/通知の呼び出しを同期ブロックにラップするためです。

  3. スレッドの原点と番号には依存しません。このアプローチを使用すると、他のスレッドを編集したり、既存のスレッドを追跡したりすることなく、任意にスレッドを追加できます。スリープ/割り込みを使用した場合は、まずスリープ中のスレッドへの参照を保持し、次に手動でそれらを1つずつ割り込みする必要があります。

これを説明するのに良い実生活の例は、古典的なレストランと、スタッフがそれらの間で通信するために使用する方法です。ウェイターは顧客の要求を中央の場所(コルクボード、テーブルなど)に置きます。ベルを鳴らすと、キッチンの作業員がそのようなリクエストに応じます。コースの準備が整うと、キッチンの担当者が再びベルを鳴らしてウェイターが気づき、お客様に案内します。


2

スリープに関する例はロックを解除せずに待機します

ここには2つのクラスがあります:

  1. Main:mainメソッドと2つのスレッドが含まれます。
  2. シングルトン:これは、2つの静的メソッドgetInstance()およびgetInstance(boolean isWait)を持つシングルトンクラスです。

    public class Main {
    
    private static Singleton singletonA = null;
    private static Singleton singletonB = null;
    
    public static void main(String[] args) throws InterruptedException {
    
    Thread threadA = new Thread() {
        @Override
        public void run() {
    
            singletonA = Singleton.getInstance(true);
    
        }
    };
    
    Thread threadB = new Thread() {
        @Override
        public void run() {
            singletonB = Singleton.getInstance();
    
            while (singletonA == null) {
                System.out.println("SingletonA still null");
            }
    
            if (singletonA == singletonB) {
                System.out.println("Both singleton are same");
            } else {
                System.out.println("Both singleton are not same");
            }
    
        }
    };
    
    threadA.start();
    threadB.start();
    
     }
    }

そして

public class Singleton {

    private static Singleton _instance;

    public static Singleton getInstance() {

    if (_instance == null) {
        synchronized (Singleton.class) {
            if (_instance == null)
                _instance = new Singleton();
        }
    }
    return _instance;

}

public static Singleton getInstance(boolean isWait) {

    if (_instance == null) {
        synchronized (Singleton.class) {
            if (_instance == null) {
                if (isWait) {
                    try {
                        // Singleton.class.wait(500);//Using wait
                        Thread.sleep(500);// Using Sleep
                        System.out.println("_instance :"
                                + String.valueOf(_instance));
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                _instance = new Singleton();
            }
        }
    }
    return _instance;

 }
}

この例を実行すると、以下の出力が得られます。

_instance :null
Both singleton are same

ここでは、threadAとthreadBによって作成されたシングルトンインスタンスは同じです。これは、threadAがロックを解放するまで、threadBが外部で待機していることを意味します。

次に、Thread.sleep(500);をコメント化してSingleton.javaを変更します。メソッドと非コメント化Singleton.class.wait(500); 。これは、Singleton.class.wait(500);のためです。メソッドthreadAはすべての獲得ロックを解放して「Non Runnable」状態に移行し、threadBは変更を取得して同期ブロックに入ります。

もう一度実行します。

SingletonA still null
SingletonA still null
SingletonA still null
_instance :com.omt.sleepwait.Singleton@10c042ab
SingletonA still null
SingletonA still null
SingletonA still null
Both singleton are not same

ここで、threadAとthreadBによって作成されたシングルトンインスタンスは同じではありません。これは、threadBが変更を同期ブロックに入力し、500ミリ秒後にthreadAが最後の位置から開始して、さらに1つのシングルトンオブジェクトを作成したためです。


2

同期ブロックから呼び出す必要があります。 wait()メソッドは常に同期ブロックから呼び出されます。つまり、メソッドは、呼び出されたwait()オブジェクトの前にオブジェクトモニターをロックする必要があります。ただし、sleep()メソッドは同期ブロックの外部から呼び出すことができます。sleep()。メソッドはオブジェクトモニターを必要としません。

IllegalMonitorStateException:実行時にスローされるwait()よりもオブジェクトロックを取得せずにメソッドが呼び出された場合IllegalMonitorStateExceptionsleep()この方法は、このような例外をスローすることはありません。

どのクラスに wait()属しているかメソッドはjava.lang.Objectクラスに属しているが、sleep()メソッドは属しているjava.lang.Threadクラスにます。

オブジェクトまたはスレッドで呼び出されました:オブジェクトで wait()メソッドが呼び出されましたがsleep()メソッドは。

スレッドの状態:wait()メソッドがオブジェクトで呼び出され、ニコラウスオブジェクトのモニターが稼働してから待機状態になり、ときにのみ実行可能状態に戻ることができ、そのスレッドnotify()またはnotifyAll()メソッドがそのオブジェクトで呼び出されます。その後のスレッドスケジューラは、そのスレッドを実行可能状態から実行状態に移行するようにスケジュールします。いつsleep()スレッドで呼び出され、それが実行されているから待機状態になり、睡眠時間がアップしている時に実行可能な状態に戻すことができます。

同期ブロックから呼び出された場合:ときwait()メソッドは、オブジェクトのロックスレッドの葉と呼ばれています。だがsleep()、同期されたブロックまたはメソッドスレッドから呼び出された場合メソッドはオブジェクトロックを残しません。

詳細についてはリファレンス


おそらくそれよりも良い参照URL。
ドリュー

2

wait()メソッドに関するOracleドキュメントページからObject

public final void wait()
  1. 別のスレッドがこのオブジェクトのnotify()メソッドまたはnotifyAll()メソッドを呼び出すまで、現在のスレッドを待機させます。つまり、このメソッドは、単に呼び出しを実行する場合とまったく同じように動作しますwait(0)
  2. 現在のスレッドは、このオブジェクトのモニターを所有している必要があります。スレッドはこのモニターの所有権を解放し、別のスレッドがこのオブジェクトのモニターでウェイクアップするのを待っているスレッドに通知するまで待機します
  3. 割り込みと偽のウェイクアップが可能
  4. このメソッドは、このオブジェクトのモニターの所有者であるスレッドによってのみ呼び出される必要があります

このメソッドはスローします

  1. IllegalMonitorStateException -現在のスレッドがオブジェクトのモニターの所有者でない場合。

  2. InterruptedException-現在のスレッドが通知を待機する前または待機中にスレッドが現在のスレッドを中断した場合。この例外がスローされると、現在のスレッドの割り込みステータスがクリアされます。

クラスのsleep()メソッドのOracleドキュメントページからThread

public static void sleep(long millis)
  1. システムタイマーとスケジューラーの精度と精度に応じて、現在実行中のスレッドを指定されたミリ秒の間スリープ(一時的に実行を停止)します。
  2. スレッドがモニターの所有権を失うことはありません。

このメソッドはスローします:

  1. IllegalArgumentException -ミリ秒の値が負の場合

  2. InterruptedException-いずれかのスレッドが現在のスレッドに割り込んだ場合。この例外がスローされると、現在のスレッドの割り込みステータスがクリアされます。

その他の主な違い:

wait()静的メソッドsleep()(クラスメソッド)とは異なり、非静的メソッド(インスタンスメソッド)です。


1

wait()一方、同期メソッド内与えられているsleep()ので、非同期メソッドの内部で与えられているwait()方法は、オブジェクトのロックを解放するが、sleep()あるいはyield()解放ありませんlock()


sleep()synchronizedブロックまたはメソッドの内部にすることができます。答えは何も説明しません。
ローンの侯爵

1
  • このメソッドwait(1000)により、現在のスレッドが最大1秒間スリープます。
    • スレッドがnotify()またはnotifyAll()メソッドの呼び出しを受け取った場合、スレッドは1秒未満しかスリープできませんでした。
  • を呼び出すsleep(1000)と、現在のスレッドが1秒間だけスリープします。
    • また、スリープ状態のスレッドはリソースのロックを保持しません。しかし、待機中のスレッドはそうです。

1
sleep(1000)正確に1秒間スリープすることは保証されません。以前に中断される場合があります。
Lucio

1
これらの投稿はとても混乱しています。このスレッドの他のすべての投稿は、スリープ状態のスレッドがロックを保持し、待機状態のスレッドがロックを保持することを示しています。同様に、図のある投稿は、notify()の呼び出しがスリープ状態のスレッドを起こすことを意味しますが、他の投稿(およびスレッドの状態図)は、interrupt()またはタイムアウト期間の経過のみがこれを行うことを意味します。私は実際にjava同時実行のコピーを自分に注文しましたが、これはずっと前に読んだはずです!
ビリンボロ2017

1

実際、これはすべてJavaドキュメントに明確に記述されています(しかし、私は答えを読んだ後でないと気づきませんでした)。

http://docs.oracle.com/javase/8/docs/api/index.html

wait()-現在のスレッドは、このオブジェクトのモニターを所有している必要があります。スレッドはこのモニターの所有権を解放し、通知オブジェクトまたはnotifyAllメソッドの呼び出しを通じて、別のスレッドがこのオブジェクトのモニターでウェイクアップするのを待っているスレッドに通知するまで待機します。次に、スレッドは、モニターの所有権を再取得できるまで待機し、実行を再開します。

sleep()-現在実行中のスレッドを、システムタイマーとスケジューラーの精度と精度に応じて、指定されたミリ秒の間スリープ(一時的に実行を停止)させます。スレッドがモニターの所有権を失うことはありません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.