java线程的“6种状态”是一个非常经典的面试考点但这6种状态是定义在java.lang.Thread.State枚举中的JVMJava虚拟机层面的状态。首先纠正一个常见误区操作系统OS层面的线程通常只有 5 种状态新建、就绪、运行、阻塞、终止而 JVM 将 OS 的“就绪”和“运行”合并为RUNNABLE并细化了阻塞的维度从而得到了这 6 种状态。下面是这 6 种状态的详细定义、生命周期以及最关键的状态切换路径解析。 1. 六种状态总览状态英文名称简单理解对应的 JVM 内部标识新建NEW线程刚被new创建但尚未调用start()。还未分配 CPU 资源。可运行RUNNABLE正在 JVM 中执行但在 OS 层面可能正在运行也可能在等待 CPU 时间片。对应 OS 的就绪运行。阻塞BLOCKED线程被锁synchronized挡住等待获取监视器锁Monitor Lock。特指同步锁阻塞。无限等待WAITING等待另一个线程显式地唤醒notify/unpark没有时间限制。必须等别人叫醒。限期等待TIMED_WAITING有超时时间的等待时间到了自动唤醒或被提前唤醒。有倒计时的等待。终止TERMINATED线程run()方法执行完毕或因异常退出。生命周期结束。 2. 核心状态切换路径附关键代码触发点状态切换是面试的重点下面的逻辑顺序就是线程从生到死的典型路线路径一新建 → 可运行 → 终止NEW-RUNNABLE调用thread.start()。RUNNABLE-TERMINATEDrun()方法执行结束正常返回或抛出异常。路径二可运行 → 无限等待WAITING→ 被唤醒后回到可运行触发进入WAITING的三种方式必须被外部显式唤醒才能离开Object.wait()必须持有对象的锁—— 需要Object.notify()/notifyAll()唤醒。Thread.join()等待其他线程死亡—— 需要被等待的线程执行完毕。LockSupport.park()JUC 并发包常用—— 需要LockSupport.unpark(thread)唤醒。⚠️关键细节被notify()唤醒后线程不会直接进入RUNNABLE而是先进入BLOCKED状态去争抢锁抢到锁后才转为RUNNABLE。路径三可运行 → 限期等待TIMED_WAITING→ 时间到/被唤醒后回到可运行进入TIMED_WAITING的常见方式都带有超时参数Thread.sleep(long millis)——不释放锁时间到了自动醒。Object.wait(long timeout)——释放锁时间到了或被notify醒。Thread.join(long millis)。LockSupport.parkNanos()/parkUntil()。路径四可运行 → 阻塞BLOCKED→ 获得锁后回到可运行当线程试图进入synchronized代码块或方法但锁被其他线程持有时进入BLOCKED。一旦持有锁的线程释放锁该线程竞争到锁后直接回到RUNNABLE。 3. 最容易混淆的易错点必看sleep和wait的状态区别Thread.sleep()处于TIMED_WAITING有超时且不释放锁。Object.wait()如果不带参处于WAITING带参处于TIMED_WAITING且释放锁。RUNNABLE并不代表 CPU 正在跑在 JVM 层面只要线程活着且没有因为锁或等待而阻塞统统标记为RUNNABLE。即使它正在 OS 队列里排队等时间片Java 层看它依然是RUNNABLE。BLOCKEDvsWAITING的根本区别BLOCKED是被动的它在等一个外部锁资源的释放等的是系统资源。WAITING是主动的它在等一个其他线程的信号等的是业务逻辑通知。面试官常问“为什么要有BLOCKED和WAITING两种” 答因为锁释放和线程通知是两种不同的同步机制。4. 状态流转图NEW --start()-- RUNNABLE --(synchronized锁竞争失败)-- BLOCKED --(锁释放)-- RUNNABLE RUNNABLE --(wait/join/park)-- WAITING --(notify/unpark/join完成)-- BLOCKED(抢锁) -- RUNNABLE RUNNABLE --(sleep/wait(timeout))-- TIMED_WAITING --(超时/唤醒)-- RUNNABLE RUNNABLE --(run()结束)-- TERMINATE