130

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

Thread.State文档:

Blocked
被阻塞等待监视器锁的线程处于此状态。

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

没有向我解释差异。

4

6 回答 6

105

区别比较简单。

在该BLOCKED状态下,一个线程即将进入一个synchronized块,但synchronized在同一对象上的一个块内当前正在运行另一个线程。然后第一个线程必须等待第二个线程退出它的块。

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

于 2013-03-28T11:24:55.280 回答
104

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

一旦通知此线程,它将无法运行。可能是其他线程也被通知(使用notifyAll())或者第一个线程还没有完成他的工作,所以它仍然被阻塞直到它有机会。这称为阻塞状态。每当一个线程试图获取对象上的锁并且某个其他线程已经持有该锁时,就会出现阻塞状态。

一旦其他线程离开并且它的这个线程机会,它移动到 Runnable 状态之后,它有资格根据 JVM 线程机制拾取工作并移动到运行状态。

于 2013-03-28T11:26:56.313 回答
37

阻塞状态和等待状态之间的重要区别在于对调度程序的影响。处于阻塞状态的线程正在竞争锁;该线程仍然算作调度程序需要服务的东西,可能会考虑到调度程序决定给运行线程多少时间(这样它就可以给阻塞在锁上的线程一个机会)。

一旦线程处于等待状态,它对系统施加的压力就会最小化,调度程序不必担心它。它处于休眠状态,直到收到通知。除了它保持一个操作系统线程被占用之外,它完全不起作用。

这就是为什么使用 notifyAll 不太理想的原因,它会导致一堆以前愉快地处于休眠状态的线程被唤醒,不会给系统带来任何负载,它们中的大多数会阻塞,直到它们可以获取锁,找到它们的条件等待是不真实的,回去等待吧。最好只通知那些有可能取得进展的线程。

(使用 ReentrantLock 而不是内部锁可以让您对一个锁有多个条件,这样您就可以确保通知的线程是一个正在等待特定条件的线程,避免在线程收到通知的情况下丢失通知错误它无法采取行动的东西。)

于 2017-05-07T12:21:46.610 回答
24

解释线程转储的简化视角:

  • WAIT - 我在等着得到一些工作,所以我现在很闲。
  • 阻塞- 我正忙着完成工作,但另一个线程挡住了我的路,所以我现在很空闲。
  • RUNNABLE ...(Native Method) - 我要求 RUN 一些本机代码(尚未完成),所以就 JVM 而言,你是 RUNNABLE 并且它不能提供任何进一步的信息。一个常见的例子是用 C 编码的本机套接字侦听器方法,它实际上正在等待任何流量到达,所以我现在很空闲。在这种情况下,这可以看作是一种特殊的等待,因为我们实际上并没有在运行(没有 CPU 消耗),但是您必须使用操作系统线程转储而不是 Java 线程转储来查看它。
于 2016-02-28T10:17:38.927 回答
2

阻塞-您的线程处于线程生命周期的可运行状态并试图获取对象锁。等待 - 您的线程处于线程生命周期的等待状态并等待通知信号进入线程的可运行状态。

于 2016-02-03T10:45:42.310 回答
-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();
        }
    }
}
}
于 2017-05-07T11:02:50.483 回答