多线程CPU高需区分真忙、假忙和调度失衡;用top -H定位高CPU线程,pstack查栈看锁等待或空转;strace/gdb分析锁争抢,perf/vmstat验证调度开销。

多线程应用导致 CPU 资源争抢,往往不是“谁抢得快”的问题,而是“谁卡住了别人”或“谁在空转耗电”。关键要区分是 真忙(有效计算)、假忙(自旋等待、死循环、锁竞争)还是 调度失衡(线程数远超 CPU 核心数)。排查需从系统层定位热点,再下沉到线程行为和同步逻辑。
先看整体负载和线程级 CPU 占用
用 top -H -p 查看目标进程下各线程的实时 CPU 使用率。注意两点:
- %CPU 列显示的是该线程占用单个逻辑 CPU 核心的百分比,所以可能超过 100%(比如 12 核机器上看到 300%,说明它占满了 3 个核)
- 重点关注持续高于 90% 的线程,记下其 TID(线程 ID),后续用于栈分析
- 同时观察 us(用户态)和 sy(内核态)占比:若 sy 高,可能是频繁系统调用(如大量锁争抢、上下文切换);若 us 高,更可能是业务逻辑或自旋等待
抓线程调用栈,识别执行卡点
对高 CPU 线程用 pstack 或 gdb -p 获取完整调用栈。重点看:
- 是否停在
pthread_mutex_lock、__lll_lock_wait等锁函数——说明在等锁,但不一定是死锁,也可能是热点锁导致排队 - 是否反复出现在同一段循环里(如 while(1)、for(;;)、无休眠的 busy-wait)——典型空转耗 CPU
- 是否在
select/poll/epoll_wait等 I/O 等待函数中却 CPU 很高?那大概率是 timeout 设置为 0 或极小值,变成了轮询
查锁竞争与死锁线索
仅靠 top 和 pstack 不足以判断锁是否被长期持有或形成环路。可结合:
-
strace -p:观察 futex 系统调用频次和阻塞时间,高频 futex_wait 是锁争抢强信号-e trace=clone,futex,mutex - 用
gdb进入后执行info threads+thread+bt,对比多个线程的锁持有/等待状态 - 若怀疑死锁,检查所有线程是否都卡在不同锁上且形成等待闭环(如线程 A 等 B 持有的锁,B 又等 A 持有的锁)
验证是否线程过载或调度异常
即使单个线程 CPU 不高,线程总数过多也会引发严重调度开销:
- 运行
cat /proc/查看当前线程数,对比系统逻辑 CPU 数(/status | grep -i 'threads' nproc) - 若线程数远超 CPU 核数(比如 100+ 线程跑在 8 核机器上),
vmstat 1中的 cs(context switch)列会明显偏高,说明内核花大量时间在线程切换 - 用
perf record -p查看内核态开销分布,若-g sleep 10 && perf report schedule、__futex_wait占比突出,就是调度和锁的问题











