Java线程状态转换,WAITING到BLOCKED,还是RUNNABLE?
Java线程状态转换,WAITING到BLOCKED,还是RUNNABLE?
SO的共识与互联网上几乎所有Java线程状态图之间似乎存在差异,特别是在调用notify()或notifyAll()后线程状态从WAITING转变的问题上...
- WAITING从不直接转变为RUNNABLE
- 线程在等待被通知之前一直处于WAITING状态...然后它变成BLOCKED...
- 一旦线程被通知,它将不会变为可运行状态...这是...阻塞状态。
因此,在SO上的共识是:在调用notify()或notifyAll()之后,线程从WAITING转变为BLOCKED;下面的图示说明了这种转变(用绿色表示)。
问题
为什么大多数网上的状态图将从WAITING到RUNNABLE的转变,而不是BLOCKED?红色的描绘显示了错误的转变;我是否遗漏了什么?
最近我一直在关注这个问题。
根据Oracle文档Thread.State,我们可以使用LockSupport.park()将当前线程置于'WAITING'或'TIMED_WAITING'状态。
所以当你尝试LockSupport.unpark()时,指定的线程将从'WAITING'/'TIMED_WAITING'状态返回到'RUNNABLE'状态。(我不确定它是否会经过'BLOCKED'状态)
我认为LockSupport.unpark()会导致指定线程的状态直接从WAITING变为RUNNABLE。
Java中的线程状态转换问题:WAITING to BLOCKED, or RUNNABLE?
在Java中,线程状态的转换是非常重要的。有时候,我们可能会遇到一个问题:为什么一个线程从WAITING状态变为RUNNABLE状态,而不是BLOCKED状态?这个问题的答案其实很简单:当一个线程从WAITING状态被唤醒时,它需要重新获取等待对象的监视器锁,这就是为什么它会进入BLOCKED状态。
根据Java官方文档中的说明,一个处于BLOCKED状态的线程是因为它正在等待获取一个监视器锁,以进入一个同步的代码块/方法,或者在调用Object.wait()方法后重新进入同步的代码块/方法。
这个问题在Java官方文档中也有详细的解释。在Object.notify()方法的文档中,它明确说明了“当一个线程被唤醒后,它将无法继续执行,直到当前线程释放该对象上的锁”。同样,在Object.wait()方法的文档中也明确说明了“线程会等待,直到重新获取到监视器的所有权,并且恢复执行”。
这样解释起来是有道理的。但是,对于TIMED_WAITING状态来说,也是这样吗?除非它是通过sleep(t)方法进入了TIMED_WAITING状态。
根据Java官方文档中Thread.State的说明,WAITING状态适用于没有参数的Object.wait()方法,而TIMED_WAITING状态适用于接受等待时间参数的重载方法。这对于两种情况都适用。至于sleep方法,线程在唤醒时并不会释放任何持有的监视器锁,它仍然拥有它们。
当一个线程被唤醒时,它需要重新获取等待对象的监视器锁,这将使线程进入BLOCKED状态。这是Java中线程状态转换的一个重要原则。了解这个原则有助于我们更好地理解线程的运行机制,并能够更好地编写多线程的程序。
解决这个问题的方法是确保在使用notify方法唤醒线程之前,当前线程释放了等待对象的监视器锁。这样,被唤醒的线程就能够重新获得监视器的所有权,并继续执行。这样,线程的状态就会正确地从WAITING转换为BLOCKED或RUNNABLE。
希望本文对于理解Java线程状态转换的原因和解决方法有所帮助。通过深入学习和理解线程的运行机制,我们可以更好地编写高效、可靠的多线程程序。
一个线程处于WAITING状态,直到通过notify获得监视器并变为RUNNABLE状态,才会进入BLOCK状态。
对于TIMEDWAITING状态同样适用,如果监视器已被其他线程持有,则即使指定的时间已经过去,线程仍然会进入BLOCK状态。
问题的原因是线程在等待某个条件满足时,被阻塞在了WAITING或TIMEDWAITING状态。当条件满足时,线程需要获得监视器才能继续执行,因此进入了BLOCK状态。解决方法是通过notify或notifyAll来唤醒等待的线程,使其获得监视器并进入RUNNABLE状态。
下面是一个简单的示例代码,演示了线程从WAITING状态到BLOCK状态再到RUNNABLE状态的过程:
public class ThreadStateTransitionExample { private static final Object monitor = new Object(); public static void main(String[] args) { Thread waitingThread = new Thread(() -> { synchronized (monitor) { try { System.out.println("Thread is waiting"); monitor.wait(); // 线程进入WAITING状态 System.out.println("Thread is running again"); } catch (InterruptedException e) { e.printStackTrace(); } } }); Thread blockingThread = new Thread(() -> { synchronized (monitor) { System.out.println("Thread is holding the monitor"); try { Thread.sleep(2000); // 模拟持有监视器的时间 } catch (InterruptedException e) { e.printStackTrace(); } } }); waitingThread.start(); blockingThread.start(); try { Thread.sleep(1000); // 等待一段时间,确保blockingThread先持有监视器 } catch (InterruptedException e) { e.printStackTrace(); } synchronized (monitor) { monitor.notify(); // 唤醒等待的线程 } } }
运行上述代码,可以看到输出结果为:
Thread is waiting Thread is holding the monitor Thread is running again
这表明线程首先进入WAITING状态,然后由于监视器被另一个线程持有而进入BLOCK状态。最后,通过notify方法唤醒等待的线程,使其重新进入RUNNABLE状态。
,当线程在等待某个条件满足时被阻塞在WAITING或TIMEDWAITING状态时,如果条件满足,线程需要获得监视器才能继续执行,因此会进入BLOCK状态。解决方法是通过notify或notifyAll来唤醒等待的线程,使其获得监视器并进入RUNNABLE状态。