JavaEE——多线程(3)

1.Java线程状态概述

Java 线程的生命周期由Thread.State枚举明确规定,共 6 种状态,分别是:

  1. 新建状态(New)
  2. 可运行状态(Runnable)
  3. 阻塞状态(Blocked)
  4. 等待状态(Waiting)
  5. 超时等待状态(Timed_Waiting)
  6. 终止状态(Terminated)

这 6 种状态构成了 Java 线程的完整生命周期,线程在运行过程中会在这些状态之间转换(除了新建和终止状态,其他状态可相互转换)。

2. 6 种核心状态详细说明

1. 新建状态(New)

  • 定义 :当创建了Thread类的实例对象,但尚未调用start()方法时,线程处于新建状态。
  • 核心特征
    1. 此时线程仅为一个 Java 对象,未被 JVM 真正启动,也未分配操作系统级别的线程资源(如栈空间、程序计数器等)。
    2. 线程尚未进入线程调度队列,无法被 CPU 调度执行。
  • 触发条件 :通过new Thread(...)创建线程实例(无论继承 Thread 类还是实现 Runnable 接口),未调用start()
  • 示例Thread thread = new Thread(() -> {});(此时 thread 处于 New 状态)
  • 状态转换 :仅能通过调用thread.start()方法,从「新建状态」转换为「可运行状态(Runnable)」,且start()方法仅能调用一次(重复调用会抛出IllegalThreadStateException)。

2.可运行状态(Runnable)

  • 定义 :调用start()方法后,线程进入可运行状态,这是 Java 虚拟机层面合并后的状态,对应操作系统层面的两个状态:就绪状态 和 运行状态
  • 核心特征
    1. 就绪状态:线程已被 JVM 启动,分配了系统资源,加入线程调度队列,等待 CPU 分配时间片(此时线程并未真正执行)。
    2. 运行状态:CPU 为线程分配了时间片,线程正在执行run()方法中的业务逻辑。
    3. Java 虚拟机不区分这两种状态,统一归为Runnable,因为线程在就绪和运行之间的切换由 CPU 调度器决定,JVM 无法干预。
  • 触发条件
    1. 新建状态线程调用start()方法,进入 Runnable 状态(就绪)。
    2. 阻塞状态 / 等待状态 / 超时等待状态的线程被唤醒 / 获取锁 / 超时后,会进入 Runnable 状态(就绪)。
  • 状态转换
    1. Runnable → Blocked:线程竞争synchronized对象锁失败时(等待锁释放)。
    2. Runnable → Waiting:调用无参的Object.wait()Thread.join()LockSupport.park()方法。
    3. Runnable → Timed_Waiting:调用带超时参数的Thread.sleep(long)Object.wait(long)等方法。
    4. Runnable → Terminated:run()方法正常执行完毕,或线程因未捕获异常终止。

3.阻塞状态(Blocked)

  • 定义 :线程因 ** 等待获取对象监视器锁(synchronized 锁)** 而被阻塞的状态,仅与synchronized关键字相关。
  • 核心特征
    1. 线程此时无法执行代码,只能等待其他持有synchronized锁的线程释放锁。
    2. 该状态仅针对synchronized锁,若使用java.util.concurrent包下的 Lock 锁(如 ReentrantLock),线程竞争锁失败时会进入「等待状态(Waiting)」,而非 Blocked 状态。
  • 触发条件
    1. 线程尝试进入synchronized方法 / 代码块,而锁已被其他线程持有。
  • 状态转换
    1. Blocked → Runnable:持有synchronized锁的线程释放锁,且当前线程成功获取到锁。
    2. Blocked → Terminated:线程在阻塞期间被中断(极少发生,或线程对象被回收)。

4.等待状态(Waiting)

  • 定义 :线程进入无超时时间的等待状态,若无其他线程主动唤醒,该线程会一直等待,永不自动返回可运行状态。
  • 核心特征
    1. 等待状态是 "无限期" 的,依赖其他线程的显式唤醒操作。
    2. 进入该状态的线程会释放已持有的锁(若有),以便其他线程执行。
  • 触发条件(常见方法)
    1. 调用Object.wait()方法(无参):需在synchronized代码块中调用,线程释放对象锁,进入等待。
    2. 调用Thread.join()方法(无参):等待被 join 的线程执行完毕,当前线程进入等待。
    3. 调用LockSupport.park()方法:无锁关联的等待,需通过LockSupport.unpark(Thread)唤醒。
  • 状态转换
    1. Waiting → Runnable:
      • 对于Object.wait():其他线程调用该对象的Object.notify()Object.notifyAll()方法唤醒当前线程。
      • 对于Thread.join():被 join 的线程执行完毕,当前线程自动唤醒。
      • 对于LockSupport.park():其他线程调用LockSupport.unpark(当前线程)唤醒。
    2. Waiting → Terminated:线程在等待期间被中断,或线程对象被回收。

5.超时等待状态(Timed_Waiting)

  • 定义 :线程进入有明确超时时间的等待状态,无需其他线程主动唤醒,超时时间到达后会自动返回可运行状态;也可在超时前被其他线程主动唤醒。
  • 核心特征
    1. 等待有 "时间限制",是 Waiting 状态的超时版本。
    2. 进入该状态的线程同样会释放已持有的锁(除Thread.sleep(long)外,sleep方法不会释放锁)。
  • 触发条件(常见方法)
    1. 调用Thread.sleep(long millis):线程休眠指定时间,不释放任何锁,超时后自动唤醒。
    2. 调用Object.wait(long millis)(带参):在synchronized代码块中调用,释放对象锁,超时自动唤醒或被notify()/notifyAll()唤醒。
    3. 调用Thread.join(long millis)(带参):等待被 join 的线程执行完毕,或超时后自动唤醒。
    4. 调用LockSupport.parkNanos(long nanos)/LockSupport.parkUntil(long deadline):带超时的 park 操作。
  • 状态转换
    1. Timed_Waiting → Runnable:
      • 超时时间到达,线程自动唤醒。
      • 超时前被其他线程主动唤醒(如Object.notify()LockSupport.unpark())。
    2. Timed_Waiting → Terminated:线程在超时等待期间被中断,或线程对象被回收。

6.终止状态(Terminated)

  • 定义:线程的生命周期完全结束,线程不再具备执行能力,也无法转换为其他任何状态。
  • 核心特征
    1. 线程的run()方法执行流程终止,线程对象可能还存在(被 GC 回收前),但线程本身已失效。
    2. 终止后的线程无法再次调用start()方法(调用会抛出IllegalThreadStateException)。
  • 触发条件(两种场景)
    1. 正常终止:run()方法中的业务逻辑全部执行完毕,线程正常退出。
    2. 异常终止:线程在执行run()方法时抛出未被捕获的异常(如 NullPointerException、InterruptedException 等),导致线程被迫终止。
  • 状态转换:无后续状态转换,线程生命周期结束。

3.关键区分

  1. Runnable 状态 vs 操作系统就绪 / 运行状态:Java 的 Runnable 是合并状态,包含操作系统的 "就绪(等待 CPU 调度)" 和 "运行(正在执行)" 两种状态,由 CPU 调度器负责切换,JVM 不感知。
  2. Blocked vs Waiting vs Timed_Waiting
    • Blocked:仅因竞争synchronized锁阻塞,有明确的 "锁等待" 目标。
    • Waiting:无超时,需主动唤醒,释放锁(大部分场景)。
    • Timed_Waiting:有超时,可自动唤醒或主动唤醒,sleep()不释放锁,其他如wait(long)释放锁。
  3. sleep() vs wait()
    • sleep(long):属于 Timed_Waiting,不释放锁,静态方法(针对当前线程)。
    • wait()/wait(long):分别属于 Waiting/Timed_Waiting,释放对象锁,实例方法(针对具体对象),需在synchronized中调用。
相关推荐
晴空了无痕6 分钟前
从 Go 基础到 K8s:一条可落地的 Go 服务端成长路线
开发语言·后端·golang·kubernetes
神明不懂浪漫8 分钟前
【第五章】Java中的继承与多态
java·开发语言
神州世通1 小时前
解密企业通信安全防线:Avaya Aura 三层安全架构深度解析
开发语言·php
AC赳赳老秦2 小时前
企业工商公开信息采集分析:OpenClaw 批量查询企业工商信息,生成企业画像报告
大数据·开发语言·python·自动化·php·deepseek·openclaw
AI多Agent协作实战派2 小时前
AI多Agent协作系统实战(十七):凌晨4点,我的AI系统在“假装工作“——3个bug同时爆炸的5小时
java·前端·bug
gaolei_eit2 小时前
Java+Ai+vue
java·spring·maven
qq_2518364572 小时前
基于java Web 动漫视频网站毕业论文
java·开发语言·前端
野生风长2 小时前
C++入门基础:从命名空间到引用与指针的全面解析
开发语言·c++
LayZhangStrive2 小时前
JUC相关的函数、注解、变量杂记
java·面试·多线程·juc
未秃头的程序猿3 小时前
给公司做了个AI客服Agent,用的Spring AI 1.0,3天上线领导拍板了
java·后端·ai编程