线程的状态
1. 通用五态模型 (The 5-State Model)
1. 新建 (New)
-
状态描述:线程对象已经被创建(比如 C++ 中
new Thread或 Java new Thread()),但还没有被启动,还没有分配 CPU 资源,也没有进入调度队列。
-
2. 就绪 (Ready / Runnable)
-
状态描述:线程万事俱备,只欠 CPU。它已经在调度器的”就绪队列”里排队了,随时可以运行,但 CPU 时间片还没轮到它。
-
关键点:在多核 CPU 下,可能有多个线程同时处于就绪态。
3. 运行 (Running)
-
状态描述:线程获得了 CPU 时间片,正在执行代码逻辑。
-
4. 阻塞 (Blocked / Waiting)
-
状态描述:线程暂停运行,让出 CPU。因为它在等待某个”事件”发生,即使给它 CPU 它也干不了活。
-
-
-
-
主动休眠:调用了
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 下使用 top或 ps命令查看线程(LWP),你会看到 STAT列,它们对应着具体的操作系统状态:
|
|
|
|
|
|
|
|
|
正在 CPU 上跑,或者在队列里排队。Linux 不区分 Running 和 Ready,都算 R。
|
|
|
|
|
浅度睡眠。等待网络数据、时钟等。可以被信号唤醒(比如 kill)。
|
|
|
Disk Sleep (Uninterruptible)
|
|
深度睡眠。通常是在等待极其重要的磁盘 I/O。不能被信号打断(kill -9都杀不掉),只能等 I/O 完成。
|
|
|
|
|
僵尸状态。线程退出了,但父进程还没帮它收尸(还没读取它的退出状态)。
|
|
|
|
|
暂停。比如被 GDB 调试断点卡住了,或者收到了 SIGSTOP信号。
|
4. 为什么需要了解这些?(开发场景)
-
-
如果系统很慢,用
top看到大量线程处于 R (Running) 状态,说明 CPU 瓶颈(算力不够)。
-
如果看到大量线程处于 D (Disk Sleep) 状态,说明 I/O 瓶颈(硬盘坏了或读写太慢)。
-
-
如果线程长期处于 S (Sleep) 状态且不处理请求,可能是死锁(在等一个永远不会释放的锁)。
-
-
为了提高性能,我们要尽量减少 Running => Blocked 的切换(上下文切换开销大)。
-
这就是为什么 Nginx、Redis、Node.js 使用 Epoll / 异步非阻塞 I/O:它们让一个线程一直处于 Running 状态处理请求,而不要因为等网络数据而进入 Blocked。