Java线程状态转换的详细过程

 更新时间:2025年09月16日 08:37:21   作者:似水流年流不尽思念  
Java线程状态转换是Java多线程编程中的关键概念,对于理解和优化并发程序至关重要,Java线程在其生命周期中经历多种状态,这些状态之间的转换是由线程调度器根据特定的策略来决定的,以下是对Java线程状态转换的详细说明,需要的朋友可以参考下

一、先明确:Java的6种线程状态(Thread.State)

这是状态转换的“基本单元”,所有转换都围绕这6种状态进行:

1.NEW(新建):线程对象已创建(如new Thread()),但未调用start(),JVM未为其分配操作系统级线程资源。

2.RUNNABLE(可运行):调用start()后进入此状态,对应操作系统线程的“就绪”和“运行中”——线程要么在等待CPU调度(就绪),要么正在CPU上执行run()方法(运行中),JVM层面不区分这两个子状态。

3.BLOCKED(阻塞):仅因竞争synchronized锁失败而暂停,等待锁释放(不涉及Lock接口的锁,Lock锁竞争会进入WAITING/TIMED_WAITING)。

4.WAITING(无限等待):线程主动调用无参等待方法,释放CPU和持有的锁,必须依赖其他线程显式唤醒(否则永久等待)。

5.TIMED_WAITING(计时等待):线程调用带超时参数的等待方法,释放资源后仅等待指定时间,超时后自动唤醒,也可被提前唤醒。

6.TERMINATED(终止):线程的run()方法执行完毕,或因未捕获异常崩溃,生命周期彻底结束。

线程状态流程图

二、完整状态转换流程(带触发条件+场景)

线程从创建到终止,会经历以下核心转换路径,不同路径对应不同业务场景:

1. 初始启动:NEW → RUNNABLE

  • 触发操作:调用线程对象的start()方法(注意:不能重复调用,否则抛IllegalThreadStateException)。
  • 底层逻辑:start()会向JVM注册线程,JVM向操作系统申请创建线程(如Linux的pthread_create),操作系统将线程加入“就绪队列”,等待CPU调度。
  • 场景:
  Thread t = new Thread(() -> { /* 任务逻辑 */ });
  System.out.println(t.getState()); // 输出 NEW
  t.start();
  System.out.println(t.getState()); // 输出 RUNNABLE(大概率,因CPU调度有延迟)

2. 可运行态内部切换:RUNNABLE(就绪)↔ RUNNABLE(运行中)

触发操作:由操作系统的CPU调度算法控制,JVM不干预。

  就绪→运行中:CPU空闲时,调度器从就绪队列选一个线程分配时间片,线程开始执行run()方法。
  运行中→就绪:线程的CPU时间片用完,或有更高优先级线程进入就绪队列,当前线程被抢占,回到就绪队列。

特点:此过程是“隐式转换”,无需代码触发,开发者无法通过Thread.State感知(始终显示为RUNNABLE)。

3. 锁竞争:RUNNABLE ↔ BLOCKED

仅针对synchronized锁的竞争,是“被动阻塞”(线程未主动放弃,因锁被占用而暂停)。

RUNNABLE → BLOCKED:

触发:线程尝试进入synchronized代码块/方法,但锁已被其他线程持有。

逻辑:线程从CPU调度队列退出,进入该锁的“阻塞队列”,等待锁释放。

BLOCKED → RUNNABLE:

触发:持有synchronized锁的线程退出同步块,释放锁。

逻辑:JVM从该锁的阻塞队列中唤醒一个线程(公平/非公平取决于JVM实现),线程重新进入就绪队列,等待CPU调度。

场景:

Object lock = new Object();
Thread t1 = new Thread(() -> {
    synchronized (lock) { /* 持有锁执行10秒 */ }
});
Thread t2 = new Thread(() -> {
    System.out.println(t2.getState()); // 先 RUNNABLE
    synchronized (lock) { /* 竞争锁失败 */ } 
    System.out.println(t2.getState()); // 竞争时变为 BLOCKED
});
t1.start();
Thread.sleep(100); // 确保t1先持有锁
t2.start();

4. 主动等待(无限):RUNNABLE ↔ WAITING

线程主动调用无参等待方法,释放CPU和锁,必须由其他线程显式唤醒(否则“卡死”)。

RUNNABLE → WAITING(3种核心触发方式):

1.线程持有synchronized锁时,调用lock.wait()(必须在同步块内,否则抛IllegalMonitorStateException)。

2.调用另一个线程的thread.join()(无参):等待目标线程执行完毕,若目标线程未结束,当前线程进入等待。

3.调用LockSupport.park()(无参):无需持有锁,直接暂停,需通过LockSupport.unpark(thread)唤醒。

WAITING → RUNNABLE(对应唤醒方式):

1.其他线程调用lock.notify()/notifyAll()(唤醒后需重新竞争锁,竞争成功才回到RUNNABLE)。

2.join()的目标线程执行完毕(自动唤醒)。

3.其他线程调用LockSupport.unpark(thread)(直接唤醒,无需竞争锁)。

场景(wait/notify):

Object lock = new Object();
Thread t1 = new Thread(() -> {
    synchronized (lock) {
        System.out.println(t1.getState()); // RUNNABLE
        lock.wait(); // 释放锁,进入 WAITING
        System.out.println(t1.getState()); // 被唤醒并重新获锁后,回到 RUNNABLE
    }
});
Thread t2 = new Thread(() -> {
    synchronized (lock) {
        lock.notify(); // 唤醒t1
    }
});
t1.start();
Thread.sleep(100);
System.out.println(t1.getState()); // 输出 WAITING
t2.start();

5. 主动等待(计时):RUNNABLE ↔ TIMED_WAITING

线程调用带超时参数的等待方法,释放资源后等待指定时间,超时后自动唤醒(也可被提前唤醒)。

RUNNABLE → TIMED_WAITING(5种核心触发方式):

1.Thread.sleep(long ms):不释放锁,仅暂停指定时间(最常用,无需持有锁)。

2.持有synchronized锁时,调用lock.wait(long ms)。

3.调用thread.join(long ms):等待目标线程指定时间,超时后不再等。

4.LockSupport.parkNanos(long nanos)/parkUntil(long deadline):带超时的暂停。

5.线程池中的线程等待任务(如ThreadPoolExecutor的awaitTermination(long, TimeUnit))。

TIMED_WAITING → RUNNABLE(2种唤醒方式):

1.等待时间到期(自动唤醒)。

2.被其他线程显式唤醒(如notify()/unpark(),与WAITING的唤醒逻辑一致)。

场景(sleep):

Thread t = new Thread(() -> {
    System.out.println(t.getState()); // RUNNABLE
    try {
        Thread.sleep(1000); // 进入 TIMED_WAITING
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
    System.out.println(t.getState()); // 超时后回到 RUNNABLE
});
t.start();
Thread.sleep(100);
System.out.println(t.getState()); // 输出 TIMED_WAITING

6. 最终终止:RUNNABLE → TERMINATED

线程生命周期的终点,一旦进入此状态,无法再回到其他状态。

触发条件:

1.线程的run()方法正常执行完毕(无异常)。

2.线程在run()方法中抛出未捕获的异常(如NullPointerException),导致线程崩溃。

3.其他线程调用thread.stop()(已废弃,会强制终止线程,可能导致资源泄漏)。

场景:

Thread t = new Thread(() -> {
    // 任务执行1秒后结束
    try { Thread.sleep(1000); } catch (InterruptedException e) {}
});
t.start();
Thread.sleep(2000); // 等待t执行完毕
System.out.println(t.getState()); // 输出 TERMINATED

三、关键注意点

1.BLOCKED vs WAITING/TIMED_WAITING:

BLOCKED是“被动等锁”(仅因synchronized锁竞争),不释放已持有的锁;

WAITING/TIMED_WAITING是“主动等待”,会释放已持有的锁(sleep()除外,不释放锁)。

2.唤醒后的锁竞争:

由wait()唤醒的线程,必须重新竞争synchronized锁,竞争成功才会从WAITING/TIMED_WAITING进入RUNNABLE,否则会进入BLOCKED状态。

3.中断(interrupt())的影响:

若线程处于WAITING/TIMED_WAITING状态时被中断(其他线程调用thread.interrupt()),会抛出InterruptedException,并清除中断标志,线程从等待状态回到RUNNABLE(需处理异常)。

BLOCKED状态的线程被中断,不会抛出异常,仅设置中断标志,状态仍为BLOCKED。

通过以上流程,可清晰理解线程在不同场景下的状态变化,以及代码操作对状态的影响。

以上就是Java线程状态转换的详细过程的详细内容,更多关于Java线程状态转换的资料请关注脚本之家其它相关文章!

相关文章

  • SpringBoot使用Filter实现签名认证鉴权的示例代码

    SpringBoot使用Filter实现签名认证鉴权的示例代码

    这篇文章主要介绍了SpringBoot使用Filter实现签名认证鉴权的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • Springboot mybais配置多数据源过程解析

    Springboot mybais配置多数据源过程解析

    这篇文章主要介绍了Springboot+mybais配置多数据源过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03
  • Java线程死锁代码详解

    Java线程死锁代码详解

    本篇文章主要介绍了Java线程死锁代码详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2021-11-11
  • Java日期操作类常见用法示例

    Java日期操作类常见用法示例

    这篇文章主要介绍了Java日期操作类常见用法,结合实例形式分析了java针对日期时间的获取、转换常见操作技巧,需要的朋友可以参考下
    2019-07-07
  • Spring无法接收List<event>的解决方案

    Spring无法接收List<event>的解决方案

    在日常开发中,我们常使用 Spring 的 @EventListener 注解来监听事件,但在处理 批量事件 时,却可能遇到一些“看似合理但无法生效”的监听方式,本文以实际具体案例为出发点,结合源码分析事件派发逻辑,并给出两种可行解决方案,需要的朋友可以参考下
    2025-04-04
  • java使用bitmap实现可回收自增id的示例

    java使用bitmap实现可回收自增id的示例

    本文主要介绍了java使用bitmap实现可回收自增id的示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2024-10-10
  • JAVA多线程抢红包的实现示例

    JAVA多线程抢红包的实现示例

    这篇文章主要介绍了JAVA多线程抢红包的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • SpringBoot 整合 JMSTemplate的示例代码

    SpringBoot 整合 JMSTemplate的示例代码

    这篇文章主要介绍了SpringBoot 整合 JMSTemplate的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • idea install 时提示jdk的某个jar包的包不存在的问题

    idea install 时提示jdk的某个jar包的包不存在的问题

    这篇文章主要介绍了idea install 时提示jdk的某个jar包的包不存在的问题,本文给大家分享解决方法,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09
  • java 静态工厂代替多参构造器的适用情况与优劣

    java 静态工厂代替多参构造器的适用情况与优劣

    这篇文章主要介绍了java 静态工厂代替多参构造器的优劣,帮助大家更好的理解和使用静态工厂方法,感兴趣的朋友可以了解下
    2020-12-12

最新评论