java线程六种状态对应jvm实际观测的实时快照:new(未启动)、runnable(运行或就绪)、blocked(等待锁)、waiting(无超时等待)、timed_waiting(带超时等待)、terminated(已结束)。

Java 线程的六种状态到底对应什么操作
Java 里 Thread.State 定义的六种状态不是理论模型,而是 JVM 实际观测到的线程快照。它们直接反映线程在 OS 调度、JVM 同步机制和代码执行之间的实时位置。
比如你调用 thread.start() 后,线程未必立刻执行 run() 方法——它先进入 RUNNABLE 状态,但可能还在等待 CPU 时间片;而 WAITING 和 TIMED_WAITING 的区别,关键就看是否传了超时参数。
-
NEW:仅当new Thread(...)完成,且start()没被调用过 -
RUNNABLE:包括“正在 CPU 上跑”和“已就绪、排队等调度”两种情况(JVM 不区分) -
BLOCKED:尝试进入synchronized块/方法,但锁被别的线程占着 -
WAITING:调用了Object.wait()、Thread.join()、LockSupport.park()且没设超时 -
TIMED_WAITING:Thread.sleep(100)、Object.wait(500)、LockSupport.parkNanos(...) -
TERMINATED:run()方法正常返回,或抛出未捕获异常后结束
为什么 isAlive() 和 getState() 返回结果经常对不上
isAlive() 是个粗粒度判断:只要线程启动过且没终止,就返回 true;哪怕它此刻正卡在 BLOCKED 或 WAITING 状态。而 getState() 返回的是瞬时状态,精度高但易变。
常见误用是拿 isAlive() == false 当作“线程已安全结束”,其实它可能是刚进 TERMINATED,也可能是还没 start 就被 GC 掉(极少见),甚至可能因 OOM 导致状态未更新。
- 监控线程是否真正完成,优先用
join()+ 超时,而不是轮询isAlive() -
getState()在多线程环境下可能刚读完就变了,别拿它做条件分支的唯一依据 -
TERMINATED状态不可逆,但 JVM 不保证状态字段立即刷新,尤其在高负载下
Thread.stop() 为什么被废弃,替代方案有哪些坑
Thread.stop() 会直接中断线程执行,强制释放所有已持有的锁,导致对象处于不一致状态——比如只写了一半的 ArrayList 内部数组,或 HashMap 正在 rehash。
现在标准做法是协作式中断:interrupt() 设置中断标志,线程自己检查 Thread.interrupted() 或捕获 InterruptedException 后清理退出。但实际中容易漏掉几个关键点:
- 阻塞 I/O(如
SocketInputStream.read())不响应中断,需配合socket.setSoTimeout()或关闭 socket - 自定义循环里忘了加
if (Thread.currentThread().isInterrupted()) break; -
InterruptedException被 catch 后没重置中断状态(正确做法是再调一次Thread.currentThread().interrupt()) - 使用
ExecutorService时,shutdownNow()本质也是发中断,但只对正在运行的任务有效,队列里的任务会被直接丢弃
线程状态切换不是免费的,哪些场景会意外放大开销
每次状态切换都涉及 JVM 与 OS 内核交互,尤其是从 RUNNABLE 进入 WAITING 或 BLOCKED,要走完整的上下文切换流程。高频切换会让 CPU 大量时间花在调度而非计算上。
典型高危模式:
- 用
wait()/notify()实现简单开关,但唤醒逻辑没配平,导致大量线程反复WAITING → RUNNABLE → BLOCKED - 短周期
Thread.sleep(1)做忙等(比如轮询文件是否存在),每毫秒一次切换,实测比纯 while 循环还慢 - 在 synchronized 块里做耗时操作(如网络请求),让其他线程长时间卡在
BLOCKED - 线程池核心数设得过大,CPU 核心少但线程多,
RUNNABLE队列积压,调度器频繁换入换出
状态本身不消耗内存,但每个线程栈默认 1MB(可调),状态混乱往往意味着线程数量失控——这才是真正吃资源的地方。










