WAIT和BLOCKED线程状态之间的区别


101

线程状态WAIT和线程状态BLOCKED有什么区别?

Thread.State文档

已阻止
该线程在等待监视器锁定时被阻止,处于此状态。

等待中
无限期等待另一个线程执行特定操作的线程处于此状态

没有向我解释差异。


检查此线程中的答案stackoverflow.com/questions/2534147/java-thread-wait-blocked此链接也可能提供进一步的说明geekexplains.blogspot.cz/2008/07/…–
Abdul

@Abdul的geekexplains链接说,线程可以通过调用Object.wait()进入阻塞状态,这是不正确的?
2013年

根据oracle docsdocs.oracle.com/javase/6/docs/api/java/lang/…的说明:由于调用以下方法之一,线程处于等待状态:Object.wait无超时,Thread.join没有超时,LockSupport.park
阿卜杜勒

根据记录,我认为@Flavio的答案比Ankit的要好一些,以防您可能考虑更改。
灰色的

Answers:


80

线程在调用wait()对象后进入等待状态。这称为等待状态。一旦线程达到等待状态,它将需要等待,直到其他线程调用notify()notifyAll()对象上。

通知此线程后,它将无法运行。可能是其他线程也被通知了(使用notifyAll()),或者第一个线程还没有完成工作,因此在获得机会之前它仍然被阻塞。这称为阻塞状态。每当线程尝试获取对象上的锁并且某个其他线程已经持有该锁时,就会发生Blocked状态。

一旦其他线程离开并且有这个线程机会,它便会基于JVM线程机制有资格进行接管工作,然后进入Runnable状态并进入运行状态。


2
您可以更好地解释它,因为您解释了线程到达这两个状态的顺序,这比单独解释两个状态中的每个状态更清晰(这是通过“五个以上”的答案完成的
Kumar Manish

7
对于所有这些,谁不知道为什么状态图的大部分(所有?)网页要求中发现,在RUNNABLE而不是BLOCKED通知()/ notifyAll的()结果:stackoverflow.com/questions/28378592/...
尼克拉斯·彼得·

假设只有一个线程并以毫秒为单位等待了一段时间;现在有可能一个线程可以直接从等待状态转到可运行状态吗?因为没有其他线程在这里锁定,因为只有单线程?
卡纳加韦卢·苏古玛'16

有一个wait(time)方法,一旦时间过去,它将返回到可运行状态。但是,如果没有指定时间,它将等待直到其他线程通知或该线程被中断。
Ankit Bansal

2
您的回答很好,但是并不能完全解释您何时尝试获取锁都可以进入“阻止”状态。它与信号/通知没有任何关系。
灰色的

90

区别相对简单。

在这种BLOCKED状态下,一个线程将要进入一个synchronized块,但是synchronized同一对象上的块中当前正在运行另一个线程。然后,第一个线程必须等待第二个线程退出其块。

在这种WAITING状态下,一个线程正在等待来自另一个线程的信号。这通常是通过调用Object.wait()或来实现的Thread.join()。然后该线程将保持这种状态,直到另一个线程调用Object.notify()或死亡。


2
说只有线程本身可以使它进入等待状态,这是正确的吗?线程B能否使线程A进入等待状态?
2013年

1
您很少Object.wait()直接使用,但是最终您会使用WAITING更高级的并发结构(例如锁,阻塞队列等)进入状态,广义上讲,每当两个线程必须协调时。
Flavio

1
根据个人经验,等待IO的线程(例如,从Socket读取)处于RUNNING状态。
Flavio

4
Java8的doc Thread.State表示:“ ...这些状态是虚拟机状态,不反映任何操作系统线程状态。” 换句话说,JVM不在乎正在运行Java代码的线程,正在等待系统调用返回的线程或正在等待时间片的线程之间的区别。这些全都RUNNABLE与JVM有关。
所罗门慢

3
添加一个线程从WAITING状态中移出时,它必须首先进入该BLOCKED状态,直到它可以获取与正在等待的对象相关联的锁为止,这可能是一个很好的补充。
灰色的

21

阻塞状态和等待状态之间的重要区别是对调度程序的影响。处于阻塞状态的线程正在争用锁。该线程仍然算作调度程序需要服务的内容,可能会被考虑到调度程序决定要分配多少时间来运行线程(以便它可以给锁在线程上的线程一个机会)。

一旦线程处于等待状态,线程对系统的压力便会降到最低,并且调度程序不必担心。它将一直处于休眠状态,直到收到通知为止。除了它使OS线程处于占用状态之外,它完全不起作用。

这就是为什么使用notifyAll不太理想的原因,它会导致一堆以前快乐地处于休眠状态的线程被唤醒,从而使系统上的任何负载都无法唤醒,它们中的大多数将阻塞,直到他们获得锁,找到它们所处的条件为止等待不是真的,然后回到等待状态。最好只通知那些有进步机会的线程。

(使用ReentrantLock而不是固有锁可以使您对一个锁具有多个条件,从而可以确保被通知的线程是正在等待特定条件的线程,避免在线程被通知时丢失通知错误。无法执行的操作。)


那是因为在监视器对象上调用notify()是其他线程的责任吗?
berimbolo

@berimbolo:我不明白您在问什么
Nathan Hughes

这是关于为什么调度程序不需要担心等待线程的原因。我想知道是否是因为另一个线程将在等待时负责调用notify。
berimbolo

@berimbolo:等待中的线程最终被通知唤醒。调度程序将决定通知哪个等待线程。
内森·休斯

很重要,您说的是自旋锁,BLOCKED并不意味着它是自旋锁
Frank Zhang

16

解释线程转储的简化透视图:

  • 等待 -我正在等待得到一些工作,所以我现在很闲。
  • 封锁 -我正忙于完成工作,但是另一个线程挡住了我的路,所以我现在很空闲。
  • RUNNABLE ...(本机方法)-我调出一些本机代码来运行(尚未完成),就JVM而言,您是RUNNABLE,它无法提供任何进一步的信息。一个常见的示例是用C编写的本机套接字侦听器方法,它实际上正在等待任何流量到达,因此我现在处于空闲状态。在那种情况下,这可以看作是一种特殊的等待,因为我们实际上根本没有在运行(不消耗CPU),但是您必须使用OS线程转储而不是Java线程转储才能看到它。

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();
        }
    }
}
}

感谢您提供的代码,但我希望您有一个文本答案,然后显示一个小的代码块。
灰色的
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.