type
Post
status
Published
date
Jun 13, 2024
slug
thread_lifecycle
summary
tags
多线程
category
Java八股文
icon
password
Java 中的线程(Thread)是实现多线程编程的重要组成部分。理解线程的生命周期对编写高效的并发程序至关重要。在 Java 中,线程的生命周期可以分为五个主要阶段:新建(New)、可运行(Runnable)、运行中(Running)、阻塞(Blocked)和终止(Terminated)。本文将详细讨论每个阶段的特点、状态转换以及相关的编程实践。

一、新建(New)

1.1 概述

当一个线程对象被创建但尚未启动时,它处于新建状态。此时,线程对象已经存在,但操作系统尚未为它分配资源。新建状态的线程通常通过以下方式创建:

1.2 状态特征

  • 线程对象已创建:线程对象已经存在于 JVM 中。
  • 尚未启动:线程的 start() 方法尚未被调用,线程还未进入可运行状态。

1.3 状态转换

新建状态的线程通过调用 start() 方法进入可运行状态:
调用 start() 方法后,JVM 会为该线程分配资源并将其调度到可运行队列中,线程进入可运行状态。

二、可运行(Runnable)

2.1 概述

线程处于可运行状态时,它已经准备好被 CPU 执行。此状态下,线程可能正在运行,也可能正在等待操作系统为其分配 CPU 时间片。可运行状态是一个通用的状态,包含了实际运行中的线程和等待 CPU 时间的线程。

2.2 状态特征

  • 已启动:线程的 start() 方法已被调用。
  • 等待调度:线程在等待操作系统的调度以获得 CPU 时间。

2.3 状态转换

可运行状态的线程可以进入运行中状态,当线程获得 CPU 时间片时,转换为运行中状态:
此外,可运行状态的线程可能因资源不可用等原因进入阻塞状态。

三、运行中(Running)

3.1 概述

当线程获得 CPU 时间片后,它进入运行中状态。在这个状态下,线程正在执行其 run() 方法中的代码。

3.2 状态特征

  • 获得 CPU:线程已被操作系统调度,正在运行。
  • 执行代码:线程正在执行其 run() 方法中的代码。

3.3 状态转换

运行中状态的线程可能因以下原因转换为其他状态:
  • 时间片结束:操作系统时间片结束,线程返回到可运行状态,等待下一个调度。
  • 阻塞操作:线程因等待 I/O 操作、获取锁等原因进入阻塞状态。
  • 终止:线程的 run() 方法执行完毕,进入终止状态。

四、阻塞(Blocked)

4.1 概述

线程处于阻塞状态时,它正在等待某种条件的满足,如等待 I/O 操作完成、等待获取锁或其他同步资源。阻塞状态的线程无法继续执行,直到阻塞条件解除。

4.2 状态特征

  • 等待条件:线程正在等待特定条件的满足,如 I/O 完成或获取同步锁。
  • 暂时停止:线程无法继续执行,直至阻塞条件解除。

4.3 状态转换

阻塞状态的线程在满足条件后可以返回到可运行状态:
  • I/O 完成:如果线程在等待 I/O 操作,操作完成后线程返回可运行状态。
  • 获取锁:如果线程在等待同步锁,锁被释放后线程返回可运行状态。
阻塞状态的线程可能因调用 wait()sleep()join() 方法进入等待状态。

五、终止(Terminated)

5.1 概述

当线程的 run() 方法执行完毕,或者因异常提前退出,线程进入终止状态。在终止状态,线程的生命周期结束,它将不再执行任何代码。

5.2 状态特征

  • 执行完毕:线程的 run() 方法正常结束,或线程因未捕获的异常而退出。
  • 不可逆转:线程进入终止状态后,无法再转换为其他状态。

5.3 状态转换

进入终止状态的线程不再转换为其他状态。通常,线程进入终止状态的原因有:
  • 正常结束run() 方法执行完毕。
  • 异常退出:线程因未捕获的异常提前退出。

六、线程状态转换图

下图展示了线程在各个状态之间的转换关系:

七、线程状态控制示例

通过一个示例代码展示如何在 Java 中控制和观察线程的状态转换:
在上述代码中,创建了一个新的线程 thread,并在不同状态下打印其状态信息。通过 thread.getState() 方法可以获取线程的当前状态。

八、线程的同步与状态

8.1 同步方法和块

为了防止线程间的资源竞争和数据不一致问题,Java 提供了同步机制。同步方法和同步块可以确保同一时刻只有一个线程访问共享资源。

8.1.1 同步方法

同步方法通过 synchronized 关键字声明,确保方法内的代码块同一时刻只由一个线程执行。

8.1.2 同步块

同步块通过 synchronized 关键字和锁对象实现,更加灵活。

8.2 等待/通知机制

Java 提供了 wait()notify()notifyAll() 方法,用于线程间的协调和通信。这些方法必须在同步块或同步方法中调用。

8.2.1 wait() 方法

wait() 方法使当前线程进入等待状态,直到被通知或中断。

8.2.2 notify() 和 notifyAll() 方法

notify() 方法唤醒一个正在等待该锁的线程,而 notifyAll() 方法则唤醒所有等待该锁的线程。

九、线程的高级特性

9.1 线程组

线程组用于将多个线程组织在一起,方便统一管理和控制。

9.2 守护线程

守护线程是一种在后台运行的线程,它们不会阻止 JVM 退出。通过调用 setDaemon(true) 方法将一个线程设置为守护线程。

十、结论

Java 中的线程生命周期管理是并发编程的核心知识之一。通过理解线程在不同状态下的行为以及如何在不同状态之间转换,开发者可以编写出更高效、安全和稳定的并发程序。无论是基本的线程创建与启动,还是高级的线程同步与通信,这些知识都是开发者在实际项目中必不可少的技能。
通过本文的详细讲解,相信读者对 Java 中线程的生命周期有了全面的理解,并能够在实际编程中灵活运用这些知识来解决多线程编程中的各种问题。
 
讲讲响应式编程ReentrantLock实现原理
Loading...