在 Java 中,线程是执行程序中的独立执行路径。线程的生命周期由 Java 虚拟机(JVM)管理,并且可以在不同的状态之间转换。线程的生命周期通常包含以下几个阶段,每个阶段有不同的状态。
线程生命周期的状态
新建状态(New):
- 当线程对象被创建时,它处于 新建状态。此时线程已经存在,但还没有开始执行。
- 线程通过
new Thread()
创建,调用start()
方法后,线程才会进入下一个状态。
Thread thread = new Thread(); // 线程处于新建状态
就绪状态(Runnable):
- 当线程调用
start()
方法时,它进入 就绪状态。这意味着线程已经准备好执行,并且等待操作系统的调度。 - 在这个状态下,线程并不一定正在执行,它可能被操作系统的线程调度程序调度到 CPU 上执行。
- Java 中的
Runnable
状态包括了操作系统层面的就绪状态和正在执行状态,因此,线程在这个状态下并不意味着它正在执行。
thread.start(); // 线程进入就绪状态
- 当线程调用
运行状态(Running):
- 当操作系统的线程调度器分配 CPU 时间片给线程时,它进入 运行状态。此时,线程开始执行
run()
方法中的代码。 - 线程运行状态是从就绪状态到 CPU 执行的实际状态。线程可以执行直到被操作系统暂停或结束。
- 当操作系统的线程调度器分配 CPU 时间片给线程时,它进入 运行状态。此时,线程开始执行
阻塞状态(Blocked):
- 如果线程在等待某个资源或条件(比如 I/O 操作或等待锁),它会进入 阻塞状态。当某个条件得到满足,线程才会恢复执行。
- 阻塞状态有以下几种:
- 等待阻塞:调用
Object.wait()
方法,线程会进入等待阻塞状态,直到被notify()
或notifyAll()
唤醒。 - 同步阻塞:当线程试图访问一个已被其他线程锁定的同步方法或代码块时,它会进入同步阻塞状态,直到获得锁。
- 等待阻塞:调用
synchronized (lock) { // 如果锁已经被其他线程持有,这个线程就会进入阻塞状态 }
等待状态(Waiting):
- 当线程调用
Object.wait()
、Thread.join()
或LockSupport.park()
等方法时,它进入 等待状态,直到其他线程通过notify()
、notifyAll()
或interrupt()
唤醒它,或者它自己恢复。 - 这种状态是线程由于等待某个事件而不能继续执行的状态。
synchronized (lock) { lock.wait(); // 线程进入等待状态 }
- 当线程调用
超时等待状态(Timed Waiting):
- 当线程调用
sleep()
、join()
(带超时参数)、wait()
(带超时参数)等方法时,它进入 超时等待状态,直到指定时间过去,或者通过其他方式被唤醒。 - 在这个状态下,线程会在指定时间内处于等待状态,并且不会响应其他线程的中断请求,除非超时或被唤醒。
Thread.sleep(1000); // 线程进入超时等待状态,休眠 1 秒
- 当线程调用
终止状态(Terminated):
- 当线程执行完毕或被强制停止时,线程进入 终止状态。此时,线程的生命周期结束。
- 线程完成其任务后,
run()
方法执行完毕,线程进入终止状态。 - 线程也可能通过调用
interrupt()
被中断,进入终止状态。
thread.join(); // 等待线程执行完成,线程进入终止状态
线程的生命周期总结
- New:线程刚创建,还没有开始执行。
- Runnable:线程准备好执行,但可能等待调度。
- Running:线程正在执行
run()
方法。 - Blocked:线程因为资源竞争(如锁)而被阻塞。
- Waiting:线程等待某个条件或事件的发生。
- Timed Waiting:线程等待指定时间,时间到后恢复执行。
- Terminated:线程执行完成,生命周期结束。
通过这些状态,线程的生命周期可以反映线程从创建到执行、等待、阻塞、终止的完整过程。线程的管理和调度主要由 Java 的线程调度器和操作系统共同决定。