Java 线程状态转换,从 WAITING 到 BLOCKED,还是 RUNNABLE?
Java thread state transition, WAITING to BLOCKED, or RUNNABLE?
SO 共识与互联网上几乎每个 Java 线程状态图之间似乎存在差异;具体来说,关于调用 notify()
或 notifyAll()
之后的线程状态转换 from WAITING
...
- WAITING never直接进入RUNNABLE
- 线程在收到通知之前一直在等待...然后它becomes阻塞...
- 一旦这个线程被通知,它will not be runnable...这是..阻塞状态。
所以对 SO 的共识是:线程在调用 notify()
或 notifyAll()
后从 WAITING
转换到 BLOCKED
;下图以绿色说明了这种转变。
问题
为什么大多数 state diagrams on the web 说明了从 WAITING
到 RUNNABLE
的过渡,而不是 BLOCKED
?红色的描述表示不正确的过渡;我错过了什么吗?
任何显示 notify
将线程从 WAITING 变为 RUNNABLE 的调用的图表都是错误的(或者使用了未阐明的快捷方式)。一旦线程从 notify
(或者甚至是虚假唤醒)中被唤醒,它就需要重新锁定它正在等待的对象的监视器。这是BLOCKED
状态。
Thread state for a thread blocked waiting for a monitor lock. A thread
in the blocked state is waiting for a monitor lock to enter a
synchronized block/method or reenter a synchronized block/method after
calling Object.wait
.
这在 Object#notify()
的 javadoc 中有解释:
The awakened thread will not be able to proceed until the current
thread relinquishes the lock on this object.
The thread then waits until it can re-obtain ownership of the monitor
and resumes execution.
最近在关注这个问题
正如 Oracle 文档 Thread.State 所说,我们可以使用 LockSupport.park() 将当前线程置于 'WAITING' 或 'TIMED_WAITING' 状态。
所以当您尝试 LockSupport.unpark() 时,指定的线程将从 'WAITING'/'TIMED_WAITING' return 到 'RUNNABLE'。 (不知道会不会经过'BLOCKED'状态)
一个线程处于WAITING状态,进入BLOCK状态,直到通过notify获取monitor变为RUNNABLE 。
同样适用于 TIMEDWAITING,它进入 BLOCK 状态,如果监视器被其他线程占用,即使指定的时间已经passed.(你的图需要更正)
值得一提的是,在 WAITING
状态下 Thread.interrupt()
方法在 lock.wait()
方法中也是如此。
Thread.interrupt()
方法首先让 WAITING
线程 BLOCKED
的 isInterrupted
标志设置为 true,只有在重新获取锁中断线程后才能抛出 InterruptedException
(这是显而易见的,因为它不能处理异常,通过之前没有独占锁的继续执行)。 (example here)
简单的说
总是WAITING -> BLOCKED
能够再次竞争锁,然后最终获得它和运行它的代码RUNNABLE
。
SO 共识与互联网上几乎每个 Java 线程状态图之间似乎存在差异;具体来说,关于调用 notify()
或 notifyAll()
之后的线程状态转换 from WAITING
...
- WAITING never直接进入RUNNABLE
- 线程在收到通知之前一直在等待...然后它becomes阻塞...
- 一旦这个线程被通知,它will not be runnable...这是..阻塞状态。
所以对 SO 的共识是:线程在调用 notify()
或 notifyAll()
后从 WAITING
转换到 BLOCKED
;下图以绿色说明了这种转变。
问题
为什么大多数 state diagrams on the web 说明了从 WAITING
到 RUNNABLE
的过渡,而不是 BLOCKED
?红色的描述表示不正确的过渡;我错过了什么吗?
任何显示 notify
将线程从 WAITING 变为 RUNNABLE 的调用的图表都是错误的(或者使用了未阐明的快捷方式)。一旦线程从 notify
(或者甚至是虚假唤醒)中被唤醒,它就需要重新锁定它正在等待的对象的监视器。这是BLOCKED
状态。
Thread state for a thread blocked waiting for a monitor lock. A thread in the blocked state is waiting for a monitor lock to enter a synchronized block/method or reenter a synchronized block/method after calling
Object.wait
.
这在 Object#notify()
的 javadoc 中有解释:
The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object.
The thread then waits until it can re-obtain ownership of the monitor and resumes execution.
最近在关注这个问题
正如 Oracle 文档 Thread.State 所说,我们可以使用 LockSupport.park() 将当前线程置于 'WAITING' 或 'TIMED_WAITING' 状态。
所以当您尝试 LockSupport.unpark() 时,指定的线程将从 'WAITING'/'TIMED_WAITING' return 到 'RUNNABLE'。 (不知道会不会经过'BLOCKED'状态)
一个线程处于WAITING状态,进入BLOCK状态,直到通过notify获取monitor变为RUNNABLE 。
同样适用于 TIMEDWAITING,它进入 BLOCK 状态,如果监视器被其他线程占用,即使指定的时间已经passed.(你的图需要更正)
值得一提的是,在 WAITING
状态下 Thread.interrupt()
方法在 lock.wait()
方法中也是如此。
Thread.interrupt()
方法首先让 WAITING
线程 BLOCKED
的 isInterrupted
标志设置为 true,只有在重新获取锁中断线程后才能抛出 InterruptedException
(这是显而易见的,因为它不能处理异常,通过之前没有独占锁的继续执行)。 (example here)
简单的说
总是WAITING -> BLOCKED
能够再次竞争锁,然后最终获得它和运行它的代码RUNNABLE
。