Thread.State.NEW仅在start()前有效,调用后立即变为RUNNABLE;RUNNABLE不保证正在执行,仅表示未阻塞;BLOCKED、WAITING、TIMED_WAITING唤醒机制不同;TERMINATED不可逆且轮询检测不可靠。

Thread.State.NEW 状态只出现在 start() 之前,不是“刚创建线程”就自动进入
很多人误以为 new Thread(runnable) 后线程就处于 NEW 状态,其实不然:对象刚构造完只是个普通 Java 对象,Thread.State 是线程实例的**运行时状态快照**,只有调用 getState() 才会返回当前状态——而此时它还没被 JVM 调度过,自然还是 NEW。
关键点在于:NEW 状态只在 start() 调用前有效;一旦调用 start(),JVM 就开始为其分配系统资源、注册到线程调度器,状态立刻变为 RUNNABLE(哪怕还没真正执行 run() 方法体)。
- 错误现象:
thread.getState() == Thread.State.NEW在start()后仍为true→ 实际是没等状态刷新就查了,或查的是另一个未启动的线程实例 - 真实场景:单元测试中验证线程初始化逻辑,需确保检查发生在
start()前且线程对象未被复用 - 注意:
NEW状态下不能调用join()或interrupt(),会抛IllegalThreadStateException
RUNNABLE 不等于“正在 CPU 上执行”,它包含 OS 层的 ready 和 running 两种底层状态
JVM 的 RUNNABLE 是对操作系统线程状态的抽象合并。Linux 下对应 TASK_RUNNING,即“已就绪可被调度”或“正在运行中”;Windows 下则覆盖 READY 和 RUNNING。这意味着:即使线程状态是 RUNNABLE,它也可能正卡在 OS 调度队列里排队,没拿到 CPU 时间片。
所以别用 getState() == RUNNABLE 来判断“代码是否跑起来了”——它不反映实际执行进度,只说明线程没被阻塞、挂起或终止。
立即学习“Java免费学习笔记(深入)”;
- 常见误判:看到状态是
RUNNABLE就认为run()已执行到某行,结果发现日志没打、变量没变 → 其实是刚进入RUNNABLE还没轮到调度 - 性能影响:高并发下大量线程处于
RUNNABLE状态,但实际 CPU 核心数有限,会导致上下文切换激增,top -H可见大量线程处于R(running or runnable)状态 -
RUNNABLE下不会响应interrupt()的中断请求(除非恰好在wait()/sleep()等可中断点),中断标志位会被设置但不抛异常
BLOCKED / WAITING / TIMED_WAITING 的区别不在“等什么”,而在“谁释放它”
三者都表示线程暂停执行,但唤醒机制完全不同:
-
BLOCKED:在等待 monitor 锁(synchronized 块/方法),由**持有锁的线程释放锁后自动唤醒**;典型场景是多个线程竞争同一把内置锁 -
WAITING:调用了Object.wait()、Thread.join()、LockSupport.park(),必须由其他线程显式调用notify()、notifyAll()、interrupt()或unpark()才能退出 -
TIMED_WAITING:带超时的等待,如Thread.sleep(1000)、Object.wait(500)、LockSupport.parkNanos(),既可能被外部唤醒,也可能到期自动恢复
容易踩的坑是混淆 wait() 和 sleep():前者释放锁,后者不释放;前者必须在 synchronized 块内调用,后者任意位置都可。用错会导致死锁或 IllegalMonitorStateException。
TERMINATED 状态不可逆,且无法通过 getState() 捕捉“刚结束”的瞬间
线程执行完 run() 方法(无论正常 return 还是抛出未捕获异常),JVM 清理其栈帧、释放本地资源后,状态才变为 TERMINATED。这个过程不是原子的,getState() 可能在清理中途返回 RUNNABLE 或 TERMINATED,取决于 JVM 实现和时机。
更关键的是:TERMINATED 线程对象不能复用,再次调用 start() 会直接抛 IllegalThreadStateException;也不能再对其调用 join()(虽然不会报错,但立即返回)。
- 调试陷阱:循环打印
thread.getState()直到变成TERMINATED,可能永远等不到——因为线程结束太快,你还没来得及查,它已经 gone - 正确做法:用
join()阻塞等待结束,而非轮询状态;若需事后确认,应在run()最后一行设标志位或发通知 - 兼容性注意:某些 JDK 版本(如早期 OpenJDK 8)在 GC 回收线程对象后,
getState()可能返回TERMINATED即使线程早已结束,不要依赖该值做业务判断
线程状态是瞬时快照,不是状态机流程图;靠轮询 getState() 推断执行逻辑,基本是在和 JVM 调度器赌时间。










