WAITスレッドとBLOCKEDスレッドの状態の違い


101

スレッド状態WAITとスレッド状態BLOCKEDの違いは何ですか?

Thread.Stateのドキュメント

ブロック
モニターロックを待機してブロックされているスレッドは、この状態です。

待機中
別のスレッドが特定のアクションを実行するのを無期限に待機しているスレッドは、この状態です。

違いを私に説明しません。


このスレッドでチェック答えはstackoverflow.com/questions/2534147/java-thread-wait-blockedこのリンクをさらに明確化する提供することもgeekexplains.blogspot.cz/2008/07/...
アブドゥル

@Abdul geekexplainsリンクは、スレッドがObject.wait()を呼び出すことでブロック状態になる可能性があると言っていますが、これは正しくありませんか?
5つ以上

oracle docsdocs.oracle.com/javase/6/docs/api/java/lang/…によると、次のメソッドのいずれかを呼び出したため、スレッドは待機状態にあります:タイムアウトなしのObject.wait、Thread.joinタイムアウトなしで、LockSupport.park
アブドゥル

ちなみに、変更を検討するのであれば、@ Flavioの答えはAnkitの答えよりも少し良いと思います。
グレイ

回答:


80

スレッドはwait()、オブジェクトを呼び出すと待機状態になります。これは待機状態と呼ばれます。スレッドが待機状態に達すると、他のスレッドが呼び出されるまで、notify()またはnotifyAll()オブジェクト上で待機する必要があります。

このスレッドが通知されると、実行できなくなります。他のスレッドにも通知される(を使用notifyAll())か、最初のスレッドが作業を完了していない可能性があります。そのため、機会が得られるまでブロックされます。これはブロック状態と呼ばます。ブロック状態は、スレッドがオブジェクトのロックを取得しようとし、他のスレッドがすでにロックを保持している場合に発生します。

他のスレッドが終了し、このスレッドが発生する可能性があると、そのスレッドはRunnable状態に移行します。その後、JVMスレッドメカニズムに基づいて作業を取得し、実行状態に移行します。


2
スレッドがこれらの2つの状態に到達する順序を説明したため、2つの状態をそれぞれ個別に説明するよりも明確に説明したため、説明がはるかによくなりました(「5つ以上」の回答
Kumar Manish

7
:RUNNABLEの代わりに、BLOCKEDに()/のnotifyAll()の結果を通知し、その状態図の(?すべての)ほとんどがWeb請求で見つかっなぜだろうすべての人々 、のためのstackoverflow.com/questions/28378592/...
ニクラス・ピーター

スレッドが1つだけあり、ミリ秒単位でしばらく待機したと想定します。スレッドが待機状態から実行可能状態に直接移行することは可能ですか?シングルスレッドのみなので他のスレッドはここでロックしませんか?
Kanagavelu Sugumar 2016年

時間が経過すると実行可能状態に戻るwait(time)メソッドがあります。ただし、時間を指定しないと、他のスレッドが通知するか、スレッドが中断されるまで待機します。
Ankit Bansal

2
あなたの答えは良いですが、ロックを取得しようとするときにいつでもブロックされた状態に入ることができることを完全に説明していません。シグナル/通知とは何の関係もありません。
グレイ

90

違いは比較的単純です。

このBLOCKED状態では、スレッドはsynchronizedブロックに入りますがsynchronized、同じオブジェクトのブロック内で現在実行中の別のスレッドがあります。最初のスレッドは、2番目のスレッドがそのブロックを終了するのを待つ必要があります。

このWAITING状態では、スレッドは別のスレッドからのシグナルを待っています。これは通常Object.wait()、またはを呼び出すことで発生しThread.join()ます。スレッドはObject.notify()、別のスレッドがを呼び出すか、終了するまで、この状態のままになります。


2
スレッドのみがそれを待機させることができると言うのは正しいですか?スレッドBはスレッドAを待機状態にすることができますか?
5つ以上

1
Object.wait()直接使用することはめったにありませんが、WAITINGロック、ブロッキングキューなど、より高レベルの同時実行構造も使用する状態になります。
フラビオ

1
個人的な経験から、IOを待機しているスレッド(ソケットからの読み取りなど)はRUNNING状態にあります。
フラビオ

4
Java8のドキュメントでThread.Stateは、「...これらの状態は仮想マシンの状態であり、オペレーティングシステムのスレッドの状態を反映していません。」つまり、JVMは、Javaコードを実行しているスレッド、システムコールが戻るのを待機しているスレッド、またはタイムスライスを待機しているスレッドの違いを気にしません。これらはすべてRUNNABLE、JVMに関する限りです。
ソロモンスロー

3
スレッドがWAITING状態から移動するとき、BLOCKED待機していたオブジェクトに関連付けられたロックを取得できるようになるまで、スレッドはまずその状態に移行する必要があることを付け加えるとよいでしょう。
グレー

21

ブロック状態と待機状態の重要な違いは、スケジューラへの影響です。ブロックされた状態のスレッドがロックを求めて競合しています。そのスレッドは依然としてスケジューラがサービスする必要があるものとして数えられ、実行中のスレッドに与える時間に関するスケジューラの決定に考慮される可能性があります(それにより、ロックでブロックされているスレッドにチャンスを与えることができます)。

スレッドが待機状態になると、スレッドがシステムに与えるストレスは最小限に抑えられ、スケジューラーはそれを心配する必要がなくなります。通知を受け取るまで休止状態になります。OSスレッドを占有し続けるという事実を除いて、それは完全に機能しません。

これが、notifyAllの使用が理想的とは言えない理由です。これにより、システムに負荷をかけずに以前は無意味に休止していた一連のスレッドが起動し、ほとんどのスレッドがロックを取得するまでブロックし、条件を見つけます。待つことは本当ではなく、待つことに戻ります。進行する可能性のあるスレッドのみに通知することをお勧めします。

(組み込みロックの代わりにReentrantLockを使用すると、1つのロックに対して複数の条件を設定できるため、通知されたスレッドが特定の条件で待機しているスレッドであることを確認でき、スレッドが通知を受けた場合の通知喪失のバグを回避できます動作できないもの。)


それは、監視オブジェクトでnotify()を呼び出すのが他のいくつかのスレッドの責任であるためですか?
berimbolo 2017

@berimbolo:私はあなたが何を求めているのか理解していません
Nathan Hughes

これは、待機中のスレッドがスケジューラーが心配する必要のないものである理由に関するものでした。それが待機している場合に別のスレッドがnotifyを呼び出す責任があるためか、と思いました。
berimbolo 2017

@berimbolo:待機中のスレッドは最終的に通知によって起こされます。スケジューラは、通知を受け取る待機スレッドを決定します。
Nathan Hughes

何かを数える、あなたはスピンロックを言っている、BLOCKEDはそれがスピンロックであることを意味しない
フランク・チャン

16

スレッドダンプを解釈するための簡略化された視点:

  • WAIT-仕事が与えられるのを待っているので、今はアイドル状態です。
  • BLOCKED-仕事を終わらせるために忙しいのですが、別のスレッドが邪魔をしているので、今はアイドル状態です。
  • RUNNABLE ...(ネイティブメソッド)-いくつかのネイティブコード(まだ完了していない)を実行するように要求しました。JVMに関する限り、実行可能であり、それ以上の情報を提供することはできません。一般的な例は、Cでコーディングされたネイティブソケットリスナーメソッドで、トラフィックが到着するのを実際に待機しているので、今はアイドル状態です。その状況では、これは特別な種類のWAITと見なすことができます。これは、実際には実行されていない(CPUの書き込みがない)ためです。JavaスレッドダンプではなくOSスレッドダンプを使用して確認する必要があります。

1
私はあなたの説明が好きです。これが、スレッドダンプを分析するために今まさに実行しようとしていることです:)
Sridhar Sarnobat

@MuhammadGelbanaええ、そうです、コメントを削除しました。
Eric Wang

1
あなたRUNNABLEは全く正しくありません。Java実行キューにあるが実行されていないか、Javaコードを実行している可能性があります。それは原産国を呼び出す必要はありません。
グレイ

1

ブロック-スレッドはスレッドライフサイクルの実行可能な状態にあり、オブジェクトロックを取得しようとしています。待機-スレッドはスレッドライフサイクルの待機状態にあり、通知信号がスレッドの実行可能な状態になるのを待機しています。


-1

この例を見てください:

スレッド状態のデモンストレーション。

/*NEW- thread object created, but not started.
RUNNABLE- thread is executing.
BLOCKED- waiting for monitor after calling wait() method.
WAITING- when wait() if called & waiting for notify() to be called.
  Also when join() is called.
TIMED_WAITING- when below methods are called:
 Thread.sleep
 Object.wait with timeout
 Thread.join with timeout
TERMINATED- thread returned from run() method.*/
public class ThreadBlockingState{

public static void main(String[] args) throws InterruptedException {
    Object obj= new Object();
    Object obj2 = new Object();
    Thread3 t3 = new Thread3(obj,obj2);
    Thread.sleep(1000);
    System.out.println("nm:"+t3.getName()+",state:"+t3.getState().toString()+
            ",when Wait() is called & waiting for notify() to be called.");
    Thread4 t4 = new Thread4(obj,obj2);
    Thread.sleep(3000);
    System.out.println("nm:"+t3.getName()+",state:"+t3.getState().toString()+",After calling Wait() & waiting for monitor of obj2.");
    System.out.println("nm:"+t4.getName()+",state:"+t4.getState().toString()+",when sleep() is called.");
}

}
class Thread3 extends Thread{
Object obj,obj2;
int cnt;
Thread3(Object obj,Object obj2){
    this.obj = obj;
    this.obj2 = obj2;
    this.start();
}

@Override
public void run() {
    super.run();
    synchronized (obj) {
        try {
            System.out.println("nm:"+this.getName()+",state:"+this.getState().toString()+",Before Wait().");
            obj.wait();             
            System.out.println("nm:"+this.getName()+",state:"+this.getState().toString()+",After Wait().");
            synchronized (obj2) {
                cnt++;
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
}
class Thread4 extends Thread{
Object obj,obj2;
Thread4(Object obj,Object obj2){
    this.obj = obj;
    this.obj2 = obj2;
    this.start();
}

@Override
public void run() {
    super.run();
    synchronized (obj) {
        System.out.println("nm:"+this.getName()+",state:"+this.getState().toString()+",Before notify().");
        obj.notify();
        System.out.println("nm:"+this.getName()+",state:"+this.getState().toString()+",After notify().");
    }
    synchronized (obj2) {
        try {
            Thread.sleep(15000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
}

コードに感謝しますが、テキストで回答してから小さなコードブロックを表示してください。
グレイ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.