线程五种状态

线程的状态

1. 通用五态模型 (The 5-State Model)

这是操作系统层面的标准定义:

1. 新建 (New)

  • 状态描述:线程对象已经被创建(比如 C++ 中 new Thread或 Java new Thread()),但还没有被启动,还没有分配 CPU 资源,也没有进入调度队列。
  • 动作:执行 start()后进入就绪态。

2. 就绪 (Ready / Runnable)

  • 状态描述:线程万事俱备,只欠 CPU。它已经在调度器的”就绪队列”里排队了,随时可以运行,但 CPU 时间片还没轮到它。
  • 关键点:在多核 CPU 下,可能有多个线程同时处于就绪态。

3. 运行 (Running)

  • 状态描述:线程获得了 CPU 时间片,正在执行代码逻辑。
  • 转换
    • 如果时间片用完 => 回到 就绪态
    • 如果等待 I/O 或锁 => 进入 阻塞态
    • 如果代码执行完毕 => 进入 终止态

4. 阻塞 (Blocked / Waiting)

  • 状态描述:线程暂停运行,让出 CPU。因为它在等待某个”事件”发生,即使给它 CPU 它也干不了活。
  • 常见原因
    • 等待 I/O:读磁盘、等网卡数据包。
    • 等待锁:抢 mutex没抢到。
    • 主动休眠:调用了 sleep()wait()
  • 恢复:当事件发生(数据来了、锁释放了),线程不会直接回到 Running,而是先回到 Ready(就绪)​ 重新排队。

5. 终止 (Terminated / Dead)

  • 状态描述:线程的任务执行完毕(正常返回)或发生异常强行退出。其生命周期结束,操作系统回收其资源(栈空间等)。

2. 状态转换图解 (逻辑流)

为了方便记忆,请脑补这个流转过程:
graph LR
New(新建) -->|start| Ready(就绪)
Ready -->|调度器选中| Running(运行)
Running -->|时间片用完| Ready
Running -->|等待IO/锁| Blocked(阻塞)
Blocked -->|事件完成| Ready
Running -->|执行结束| Terminated(终止)
重点考点:
  • Running =》 Blocked:是线程主动请求(读取文件)或被动限制(抢锁失败)。
  • Blocked =》 Running这是不可能的!​ 阻塞结束后,必须先回 Ready​ 排队,不能插队直接运行。

3. Linux 视角下的线程状态 (实战)

如果你在 Linux 下使用 topps命令查看线程(LWP),你会看到 STAT列,它们对应着具体的操作系统状态:
符号
状态名称
对应通用模型
解释
R
Running/Runnable
运行​ 或 就绪
正在 CPU 上跑,或者在队列里排队。Linux 不区分 Running 和 Ready,都算 R。
S
Sleep (Interruptible)
阻塞
浅度睡眠。等待网络数据、时钟等。可以被信号唤醒(比如 kill)。
D
Disk Sleep (Uninterruptible)
阻塞
深度睡眠。通常是在等待极其重要的磁盘 I/O。不能被信号打断kill -9都杀不掉),只能等 I/O 完成。
Z
Zombie
终止
僵尸状态。线程退出了,但父进程还没帮它收尸(还没读取它的退出状态)。
T
Stopped
阻塞
暂停。比如被 GDB 调试断点卡住了,或者收到了 SIGSTOP信号。

4. 为什么需要了解这些?(开发场景)

  1. 性能分析
    • 如果系统很慢,用 top看到大量线程处于 R (Running)​ 状态,说明 CPU 瓶颈(算力不够)。
    • 如果看到大量线程处于 D (Disk Sleep)​ 状态,说明 I/O 瓶颈(硬盘坏了或读写太慢)。
  2. 死锁排查
    • 如果线程长期处于 S (Sleep)​ 状态且不处理请求,可能是死锁(在等一个永远不会释放的锁)。
  3. 高并发编程
    • 为了提高性能,我们要尽量减少 Running => Blocked​ 的切换(上下文切换开销大)。
    • 这就是为什么 Nginx、Redis、Node.js 使用 Epoll / 异步非阻塞 I/O:它们让一个线程一直处于 Running​ 状态处理请求,而不要因为等网络数据而进入 Blocked

发表评论