Java 线程状态转换,WAITING 到 BLOCKED,还是 RUNNABLE?
Posted
技术标签:
【中文标题】Java 线程状态转换,WAITING 到 BLOCKED,还是 RUNNABLE?【英文标题】:Java thread state transition, WAITING to BLOCKED, or RUNNABLE? 【发布时间】:2015-04-07 08:27:07 【问题描述】:SO 共识和网上几乎所有的 Java 线程状态图似乎都有出入;具体来说,关于在调用notify()
或notifyAll()
之后的线程状态转换从 WAITING
...
所以对SO的共识是:调用notify()
或notifyAll()
后,线程从WAITING
转换为BLOCKED
;下图以绿色显示了这种过渡。
问题
为什么大多数state diagrams on the web 说明了从WAITING
到RUNNABLE
的转换,而不是BLOCKED
?红色表示不正确的过渡;我错过了什么吗?
【问题讨论】:
根据您的评论,我为什么要问绘制图表的人他们并不了解? :-) 我说“不要或没有”。如果你问他们,他们可能会发现他们错了。或者他们可能已经发现了。 所以你是说我的图表比大约 106,000 个 Google 结果更准确?地狱! 如果是这样,TIMED_WAIT
有什么特别之处?为什么直接回到RUNNABLE
,而不是转到BLOCKED
?
如果您需要,还有一些更清晰的答案。 ***.com/q/15680422/2361308
【参考方案1】:
值得一提的是,Thread.interrupt()
方法在WAITING
状态期间,而在lock.wait()
方法中也是如此。
Thread.interrupt()
方法将首先使WAITING
线程BLOCKED
将isInterrupted
标志设置为true,并且只有在重新获得锁后被中断的线程才能抛出InterruptedException
(这很明显,因为它无法处理异常,通过在没有排他锁的情况下继续执行)。 (example here)
简单来说
总是WAITING -> BLOCKED
能够再次竞争锁,然后最终获得它并运行它的代码RUNNABLE
。
【讨论】:
【参考方案2】:处于WAITING状态的线程进入BLOCK状态,直到通过notify获取monitor,变为RUNNABLE。
同样适用于 TIMEDWAITING,它进入 BLOCK 状态,如果监视器被其他线程持有,即使指定的时间已经过去。(你的图表需要更正)
【讨论】:
【参考方案3】:我最近正在关注这个问题。
正如 Oracle 文档 Thread.State 所说,我们可以使用 LockSupport.park() 将当前线程置于“WAITING”或“TIMED_WAITING”状态。
所以当你尝试LockSupport.unpark() 时,指定的线程将从'WAITING'/'TIMED_WAITING' 返回到'RUNNABLE'。 (我不确定它是否会进入 'BLOCKED' 状态)
【讨论】:
我认为LockSupport.unpark()会直接导致指定线程状态由WAITING变为RUNNABLE。【参考方案4】:任何显示 notify
调用将线程从 WAITING 变为 RUNNABLE 的图表都是错误的(或正在使用未明确的快捷方式)。一旦线程从notify
(甚至是虚假唤醒)中唤醒,它需要重新锁定它正在等待的对象的监视器。这是BLOCKED
状态。
线程阻塞等待监视器锁的线程状态。一根线 处于阻塞状态正在等待监视器锁进入 同步块/方法或在之后重新输入同步块/方法 打电话给
Object.wait
。
这在Object#notify()
的javadoc中有解释:
被唤醒的线程将无法继续,直到当前 线程放弃对该对象的锁定。
和Object#wait()
线程然后等待,直到它可以重新获得监视器的所有权 并继续执行。
【讨论】:
有道理。但是,那么TIMED_WAITING
肯定也是这样吗?
除非它因为sleep(t)
而进入TIMED_WAITING
状态。
@mystarrocks 根据Thread.State
javadoc,WAITING
用于无参数Object#wait
,而TIMED_WAITING
用于接受等待时间的过载。是的,这适用于两者。关于sleep
,线程不会解锁任何持有的监视器,它在唤醒时仍然拥有它们。以上是关于Java 线程状态转换,WAITING 到 BLOCKED,还是 RUNNABLE?的主要内容,如果未能解决你的问题,请参考以下文章