线程状态 WAIT 和线程状态 BLOCKED 的区别是什么?
返回文章页面 线程,国家文件:
被屏蔽了 等待监视器锁定时阻塞的线程处于此状态。 等待 无限期地等待另一个线程执行特定操作的线程处于这种状态
被屏蔽了 等待监视器锁定时阻塞的线程处于此状态。
等待 无限期地等待另一个线程执行特定操作的线程处于这种状态
不能解释我们之间的区别。
区别相对简单。
在 BLOCKED状态下,一个线程即将进入 synchronized块,但是当前在同一对象的 synchronized块内运行着另一个线程。然后,第一个线程必须等待第二个线程退出其块。
BLOCKED
synchronized
在 WAITING状态下,一个线程正在等待来自另一个线程的信号。这通常是通过调用 Object.wait()或 Thread.join()来实现的。然后,该线程将保持这种状态,直到另一个线程调用 Object.notify()或死亡。
WAITING
Object.wait()
Thread.join()
Object.notify()
一旦线程对 Object 调用 wait(),它就进入等待状态。这就是所谓的 等待状态。一旦线程达到等待状态,它将需要等待,直到其他线程调用对象上的 notify()或 notifyAll()。
wait()
notify()
notifyAll()
一旦通知此线程,它将不能运行。可能还会通知其他线程(使用 notifyAll()) ,或者第一个线程尚未完成其工作,因此它仍然被阻塞,直到获得机会。这就是所谓的 被屏蔽了状态。每当一个线程试图获取对象上的锁,而其他线程已经持有该锁时,就会出现阻塞状态。
一旦其他线程离开,并且有这个线程的机会,它就会转移到 Runnable 状态,然后它就有资格基于 JVM 线程机制拾取工作,并转移到运行状态。
阻塞-线程处于线程生命周期的可运行状态,并尝试获取对象锁。 等待-您的线程处于线程生命周期的等待状态,并等待通知信号进入线程的可运行状态。
解释线程转储的简化视角:
看这个例子:
线程状态的演示。
/*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(); } } } }
阻塞状态和等待状态之间的重要区别是对调度程序的影响。处于阻塞状态的线程正在争夺一个锁; 这个线程仍然算作调度程序需要服务的东西,可能被计入调度程序关于给运行线程多少时间的决定中(这样它就可以给锁上阻塞的线程一个机会)。
一旦线程处于等待状态,它给系统带来的压力就会最小化,调度程序就不必担心这个问题了。在收到通知之前,它一直处于休眠状态。除了事实上,它保持一个操作系统线程占用它是完全出局。
这就是为什么使用 notifyAll 不够理想的原因,它会导致一大堆之前愉快休眠的线程在系统上没有加载就被唤醒,其中大多数线程将会阻塞,直到它们能够获得锁,发现它们等待的条件不是真的,然后回到等待状态。最好只通知那些有机会取得进展的线程。
(使用 ReentrantLock 代替内部锁可以让你为一个锁设置多个条件,这样你就可以确保通知的线程是一个正在等待特定条件的线程,避免线程因为无法执行某些操作而被通知丢失通知的 bug