【并发编程】线程状态解析
1. 线程的几种状态
在Java中,一个线程从创建到消亡会经历新建状态(New)、就绪状态(Runnable)、运行状态(Running)、阻塞状态(Blocked)和死亡状态。在运行过程中,线程会在这几个状态之间流转。
下面对这几种状态做下简单解释:
-
新建状态(New) 新创建了一个线程对象。
-
就绪状态(Runnable) 线程对象创建后,其他线程调用了该对象的start()方法。该状态的线程位于可运行线程池中,变得可运行,等待获取CPU的使用权。
-
运行状态(Running) 就绪状态的线程获取了CPU,执行程序代码。
-
阻塞状态(Blocked) 阻塞状态是线程因为某种原因放弃CPU使用权,暂时停止运行。直到线程进入就绪状态,才有机会转到运行状态。阻塞的情况分三种
等待阻塞(WAITING):运行的线程执行wait()方法,JVM会把该线程放入等待池中。
同步阻塞(BLOCKED):运行的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池中。
其他阻塞(TIMED_WAITING):运行的线程执行sleep()或join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。 -
死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。
2. 三种阻塞状态的对比。
对于线程的新建、就绪、运行和死亡状态,我们都比较好理解。线程的三种阻塞状态的含义可能会让人比较困惑。下面就来解释下这三种状态的区别:
1. 等待阻塞状态(TIMED_WAITING)
Java文档官方定义TIMED_WAITING状态为:“一个线程在一个特定的等待时间内等待另一个线程完成一个动作会在这个状态”。调用下面的这些方法会让线程进入TIMED_WAITING状态。
- Thread#sleep();
- Object#wait() 并加了超时参数;
- Thread#join() 并加了超时参数;
- LockSupport#parkNanos();
- LockSupport#parkUntil()。
2. WAITING状态
Java文档官方定义WAITING状态是:“一个线程在等待另一个线程执行一个动作时在这个状态。”
当线程调用以下方法时会进入WAITING状态:
- Object#wait() 而且不加超时参数
- Thread#join() 而且不加超时参数
- LockSupport#park()。
在对象上的线程调用了Object.wait()会进入WAITING状态,直到另一个线程在这个对象上调用了Object.notify()或Object.notifyAll()方法才能恢复。一个调用了Thread.join()的线程会进入WAITING状态直到一个特定的线程来结束。
2. BLOCKED状态
Java文档官方定义BLOCKED状态是:“这种状态是指一个阻塞线程在等待monitor锁。”