Java线程的生命周期(附带实例)
在 Java 中,任何对象都有生命周期,线程也不例外。线程有新建(New)、就绪(Runnable)、运行(Running)、阻塞(Blocked)和死亡(Terminated)5 种状态,从新建到死亡称之为线程的生命周期,如下图所示。

图 1 线程的生命周期及状态转换
当线程对象调用 start() 方法之后,该线程处于就绪状态,JVM 会为它创建方法调用栈和程序计数器。处于就绪状态的线程并没有开始运行,只是表示该线程可以运行了。获得 CPU 的使用权之后,线程即可开始运行。
注意,启动线程使用的是 start() 方法,而不是 run() 方法!如果直接调用 run() 方法,系统会把当前的线程识别为一个普通的对象,而 run() 方法也就是一个普通的方法,并不是线程的执行体。
接下来,通过案例来演示线程的启动。
阻塞状态是指线程因为一些原因放弃 CPU 使用权,暂时停止运行。当线程处于阻塞状态时,Java 虚拟机不会给线程分配 CPU,直到线程重新进入就绪状态,它才有机会转换到运行状态。
下面列举一下线程由运行状态转换成阻塞状态的原因,以及如何从阻塞状态转换成就绪状态:
线程一旦转换为死亡状态,就不能运行且不能转换为其他状态。
注意,不要对处于死亡状态的线程调用 start() 方法,程序只能对新建状态的线程调用 start() 方法。判断线程是否死亡可以使用线程的 isAlive() 方法:当线程处于就绪、运行、阻塞这3种状态时,该方法返回 true;当线程处于新建和死亡状态时,该方法返回 false。

图 1 线程的生命周期及状态转换
新建状态和就绪状态
当程序使用 new 关键字创建一个线程后,该线程处于新建状态,此时 JVM 给它分配一块内存,但不可运行。当线程对象调用 start() 方法之后,该线程处于就绪状态,JVM 会为它创建方法调用栈和程序计数器。处于就绪状态的线程并没有开始运行,只是表示该线程可以运行了。获得 CPU 的使用权之后,线程即可开始运行。
注意,启动线程使用的是 start() 方法,而不是 run() 方法!如果直接调用 run() 方法,系统会把当前的线程识别为一个普通的对象,而 run() 方法也就是一个普通的方法,并不是线程的执行体。
接下来,通过案例来演示线程的启动。
public class Demo { public static void main(String[] args) throws InterruptedException { new MyThread().run(); new MyThread().run(); } } class MyThread extends Thread { @Override public void run() { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + " " + i); } } }程序的运行结果如下:
main 0
main 1
main 2
main 3
main 4
main 0
main 1
main 2
main 3
main 4
运行状态和阻塞状态
运行状态是指处于就绪状态的线程占用了 CPU,执行程序代码。并发执行时,如果 CPU 的占用时间超时,则会执行其他线程。只有处于就绪状态的线程才可以转换到运行状态。阻塞状态是指线程因为一些原因放弃 CPU 使用权,暂时停止运行。当线程处于阻塞状态时,Java 虚拟机不会给线程分配 CPU,直到线程重新进入就绪状态,它才有机会转换到运行状态。
下面列举一下线程由运行状态转换成阻塞状态的原因,以及如何从阻塞状态转换成就绪状态:
- 当线程调用了某个对象的 suspend() 方法时,会使线程进入阻塞状态,如果想进入就绪状态,需要使用 resume() 方法唤醒该线程;
- 当线程试图获取某个对象的同步锁时,如果该锁被其他线程持有,则当前线程就会进入阻塞状态,如果想从阻塞状态进入就绪状态,必须获取到其他线程持有的锁;
- 当线程调用了 Thread 类的 sleep() 方法时,也会使线程进入阻塞状态,在这种情况下,需要等到线程睡眠的时间结束,线程会自动进入就绪状态;
- 当线程调用了某个对象的 wait() 方法时,也会使线程进入阻塞状态,如果想进入就绪状态,需要使用 notify() 或 notifyAll() 方法唤醒该线程;
- 当在一个线程中调用了另一个线程的 join() 方法时,会使当前线程进入阻塞状态,在这种情况下,要等到新加入的线程运行结束才会结束阻塞状态,进入就绪状态。调用 join() 方法,意味着线程插队。
注意,线程从阻塞状态只能进入就绪状态,不能直接进入运行状态。
死亡状态
线程会以如下方式结束,结束之后线程就处于死亡状态:- 线程的 run() 方法正常执行完毕,线程正常结束;
- 线程抛出异常(Exception)或错误(Error)导致线程死亡;
- 调用线程对象的 stop() 方法结束线程。
线程一旦转换为死亡状态,就不能运行且不能转换为其他状态。
注意,不要对处于死亡状态的线程调用 start() 方法,程序只能对新建状态的线程调用 start() 方法。判断线程是否死亡可以使用线程的 isAlive() 方法:当线程处于就绪、运行、阻塞这3种状态时,该方法返回 true;当线程处于新建和死亡状态时,该方法返回 false。