You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java Object.notifyAll()长期阻塞且CPU高占问题排查求助

问题背景与现象

我们的大型企业级电信应用运行在RHEL6.10系统的OpenJDK8(25.171-b10)上,生产环境中随机出现以下异常:

  • 进程CPU占用率骤升
  • 最终因Java堆内存接近耗尽引发内存拥堵

通过分析Java线程转储,发现某线程在notifyAll()方法内长期阻塞(时长可达数分钟),且阻塞期间CPU占用居高不下。该线程的栈跟踪如下:

"pool-5-thread-1" #432 prio=5 os_prio=0 tid=0x00007f7c85a57000 nid=0x37fe runnable [0x00007f7c3cba0000]
   java.lang.Thread.State: RUNNABLE
       at java.lang.Object.notifyAll(Native Method)
       at gov.nist.javax.sip.parser.Pipeline.close(Pipeline.java:165)
       - locked <0x00000005c16007b8> (a java.util.LinkedList)
       at gov.nist.javax.sip.stack.NioTcpMessageChannel.close(NioTcpMessageChannel.java:258)
       at gov.nist.javax.sip.stack.ConnectionOrientedMessageChannel.close(ConnectionOrientedMessageChannel.java:203)
       at gov.nist.javax.sip.stack.SocketTimeoutAuditor.runTask(SocketTimeoutAuditor.java:74)

相关代码逻辑

我们的Pipeline类使用Java wait/notify机制实现线程同步:

  • 私有成员buffList为LinkedList类型
  • 读取线程在buffList上同步并调用wait(),代码片段:
public int read() throws IOException {
    synchronized (this.buffList) {
       // ... 其他逻辑
       this.buffList.wait();
       // ... 其他逻辑
    }
}
  • 当有数据处理或需要关闭时,独立线程调用notifyAll(),close()方法片段:
public void close() throws IOException {
    // ... 其他逻辑
    synchronized (this.buffList) {
        this.buffList.notifyAll();
    }
}

该机制通常运行正常,但此异常仅在生产环境出现,无法复现,请求排查思路。

排查思路

1. 分析notifyAll()引发的连锁CPU消耗

notifyAll()本身是轻量本地方法,不会直接导致高CPU,但唤醒大量等待线程后,这些线程会竞争锁并执行后续逻辑,可能引发CPU飙升:

  • 检查read()方法中wait()唤醒后的逻辑,是否存在循环、大量计算或锁竞争场景
  • 通过多次线程转储对比,统计问题发生时等待buffList锁的线程数量

2. 验证OpenJDK版本的已知Bug

OpenJDK8早期版本(如25.171-b10)可能存在线程唤醒、锁调度相关的Bug:

  • 核对OpenJDK8的Bug数据库,确认是否存在notifyAll()或LinkedList同步相关的性能异常Bug
  • 尝试升级到OpenJDK8的较新补丁版本(如u372及以上),观察问题是否消失

3. 关联内存耗尽与CPU高耗的因果关系

内存接近耗尽会触发频繁GC,间接干扰线程调度:

  • 分析问题发生时的GC日志,查看是否存在Full GC频繁、Old区内存溢出预警
  • 检查buffList中的元素是否未被及时清理,导致内存占用持续增长,引发GC风暴进而干扰线程正常调度

4. 生产环境实时数据采集

由于问题无法复现,需在生产环境部署监控工具捕获异常细节:

  • 定时用jstack采集线程转储,对比异常前后的线程状态变化
  • 用jstat监控GC频率与内存占用,关联CPU高耗的时间点
  • 用perf工具分析进程CPU热点,定位具体的用户态或内核态函数(重点关注线程调度、锁相关的内核函数)

5. 核查锁的持有与释放逻辑

虽然栈信息显示线程已持有buffList锁,仍需确认:

  • read()方法中wait()被唤醒后,是否存在长时间持有锁的逻辑,导致其他线程竞争加剧
  • close()方法在调用notifyAll()前后,是否有其他耗时操作,间接导致线程状态异常

6. 排查操作系统层面影响

RHEL6.10的内核版本可能存在线程调度或锁相关问题:

  • 检查系统日志(/var/log/messages)中是否有内核级线程调度异常、锁竞争告警
  • 对比生产与测试环境的内核参数(如vm.swappiness、sched_rt_runtime_us等),确认配置差异

内容的提问来源于stack exchange,提问作者Pavlos Maragkos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 00:54:29