Java线程中,Blocked,Wait,以及TIMED_WAIT的区别
根据jdk1.6的api,java的Thread类,定义了六个状态:
线程状态。线程可以处于下列状态之一:
-
NEW
至今尚未启动的线程处于这种状态。 -
RUNNABLE
正在 Java 虚拟机中执行的线程处于这种状态。 -
BLOCKED
受阻塞并等待某个监视器锁的线程处于这种状态。 -
WAITING
无限期地等待另一个线程来执行某一特定操作的线程处于这种状态。 -
TIMED_WAITING
等待另一个线程来执行取决于指定等待时间的操作的线程处于这种状态。 -
TERMINATED
已退出的线程处于这种状态。
在给定时间点上,一个线程只能处于一种状态。这些状态是虚拟机状态,它们并没有反映所有操作系统线程状态。
其中,Blocked状态以及Waiting以及Timed_waitting都会导致线程暂停运行。但是,Blocked以及waitting状态是有区别的。查询Blocked以及Waiting的api可知:
如图所示,BLOCKED是由于等待某个监视器锁而使得线程切换到此状态的,而wait是因为调用了
- 不带超时值的 Object.wait
- 不带超时值的 Thread.join
- LockSupport.park
三个方法中的一个,使得线程进入了wait状态。这是从原因上讲的区别。
此处,着重分析一下object.wait,这个方法是继承自Object父类的方法,此方法的实现依赖于本地实现。Object.wait的api如下:
如图所示,线程要想调用object.wait来使得自己变成waitting状态,首先需要拥有object的monitor对象。如果不具有该object的monitor对象,则无法变成waitting状态,同时会抛出IllegalMonitorStateException异常
如何才能拥有object的monitor对象呢?参考api:
总结如下:
使得线程变成waitting状态有以下几种方法:
调用Object对象的wait方法,但没有指定超时值。
调用Thread对象的join方法,但没有指定超时值。
调用LockSupport对象的park方法。
使得线程变成timed_waitting状态有以下几种方法:
调用Thread.sleep方法。
调用Object对象的wait方法,指定超时值。
调用Thread对象的join方法,指定超时值。
调用LockSupport对象的parkNanos方法。
调用LockSupport对象的parkUntil方法。
使得线程变成blocked状态有以下方法:
进入一个synchronized代码块失败
进入一个synchronized方法失败
在调用了object.wait之后,被其他线程object.notify唤醒之后,重新进入同步代码块或者同步方法失败。
Object.wait()
1. 前提:必须持有Object的monitor对象
2. 效果1:使得线程变为了waitting状态
3. 效果2:释放所有通过synchronized模式已经获取到的锁
4. 效果3:将本线程加入到了object的等待池中
Thread.sleep()的效果:
1前提:无需任何前提
2效果1:使得线程变为了timed_waitting状态,但是不释放已经获取到的锁资源