WAIT 和 BLOCKED 线程状态的区别

Posted

技术标签:

【中文标题】WAIT 和 BLOCKED 线程状态的区别【英文标题】:Difference between WAIT and BLOCKED thread states 【发布时间】:2013-03-18 19:22:40 【问题描述】:

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

Thread.State documentation:

已屏蔽 阻塞等待监视器锁的线程处于此状态。

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

没有向我解释差异。

【问题讨论】:

在这个线程***.com/questions/2534147/java-thread-wait-blocked检查答案也这个链接可以提供进一步的澄清geekexplains.blogspot.cz/2008/07/… @Abdul geekexplains 链接说线程可以通过调用 Object.wait() 进入阻塞状态,这是不正确的吗? 根据 oracle 文档docs.oracle.com/javase/6/docs/api/java/lang/…:由于调用以下方法之一,线程处于等待状态:Object.wait 没有超时,Thread.join 没有超时,LockSupport.park 作为记录,我认为@Flavio 的答案比 Ankit 的要好一些,以防您可能考虑更改。 【参考方案1】:

区别比较简单。

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

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

【讨论】:

说只有线程本身可以让它进入等待是否正确? Thread-B 可以让 Thread-A 进入 WAIT 状态吗? 你很少直接使用Object.wait(),但你最终会进入WAITING状态,同时使用更高级的并发结构——比如锁、阻塞队列等......两个线程必须协调。 从个人经验来看,等待IO(例如从Socket读取)的线程处于RUNNING状态。 Thread.State 的 Java8 文档说:“...这些状态是虚拟机状态,不反映任何操作系统线程状态。”换句话说,JVM 并不关心运行 Java 代码的线程、等待系统调用返回的线程或等待时间片的线程之间的区别。就 JVM 而言,这些都只是 RUNNABLE 最好补充一点,当线程从WAITING 状态移动时,它必须首先进入BLOCKED 状态,直到它可以获取与其正在等待的对象关联的锁开。【参考方案2】:

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

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

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

【讨论】:

您解释得更好,因为您解释了线程到达这两种状态的顺序,这比单独解释两种状态中的每一种更清楚(由“超过五个”完成)的回答 对于那些想知道为什么大多数(全部?)在网络中发现的状态图声称 notify()/notifyAll() 导致 RUNNABLE 而不是 BLOCKED 的人:***.com/questions/28378592/…跨度> 假设只有一个线程并等待了一段时间,单位为毫秒;现在是否有可能一个线程可以直接从等待状态进入可运行状态?因为没有其他线程在这里锁定,因为只有单线程? 有一个 wait(time) 方法,一旦时间过去,它就会回到可运行状态。但是如果没有指定时间,它会一直等到其他线程通知或者线程被中断。 您的回答很好,但并不能完全说明您可以在任何时候尝试获取锁时进入 Blocked 状态。它与信号/通知无关。【参考方案3】:

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

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

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

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

【讨论】:

是不是因为在监视器对象上调用 notify() 是其他线程的责任? @berimbolo:我不明白你在问什么 这是关于为什么等待线程不是调度程序需要担心的事情。我想知道这是不是因为另一个线程在等待时将负责调用 notify。 @berimbolo:等待的线程最终被通知唤醒。调度程序将决定通知哪个等待线程。 如果应该避免这种行为,notify 是要使用的。但只是为了一些认为notify 总是更好的人的信息。 notifyAll 是如果您的应用程序应该在没有类似死锁的情况下进行的情况下使用的(如果您的应用程序有可能处于这种情况并且如果发生这种情况,您的应用程序将无法按您的预期工作)由于“错过的信号"(在这里,预期的线程错过了信号,因为信号到达了其他一些不是预期的线程)见***.com/a/3186336/2859238【参考方案4】:

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

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

【讨论】:

我喜欢你的解释。这正是我现在在分析线程转储时要做的事情:) @MuhammadGelbana 是的,你是对的,我已经删除了评论。 您的RUNNABLE 不太正确。它可能在 Java 运行队列中但未执行,或者它可能正在执行 Java 代码。它不必呼唤本土。【参考方案5】:

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

【讨论】:

【参考方案6】:

看这个例子:

线程状态演示。

/*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();
        
    


【讨论】:

感谢您的代码,但我希望您有一个文本答案,然后显示一个 small 代码块。 如果代码非常清晰可以推理,那将很有用

以上是关于WAIT 和 BLOCKED 线程状态的区别的主要内容,如果未能解决你的问题,请参考以下文章

sleep() 和 wait() 的区别

wait-ify工作原理(学习笔记)

多线程-synchronized

线程基本介绍

java多线程总结

线程的状态