高并发问题与排查

一、常见高并发底层问题

1. 锁竞争 & 上下文切换

(1)锁竞争

  • 现象:大量线程争抢同一把锁,大量 BLOCKED 线程,请求排队、接口 rt 飙升、吞吐量下降。
  • 原因:
    1. synchronized / ReentrantLock 锁粒度过大
    2. 共享变量无脑加锁,串行化严重
    3. 全局唯一大锁,并发退化串行
  • 后果:锁等待耗时、服务吞吐上不去、高峰期雪崩。

(2)上下文切换

CPU 线程来回切换执行:

  • 线程过多、频繁阻塞 / 唤醒、竞争激烈,都会触发频繁上下文切换
  • 每次切换:保存现场 → 恢复现场,消耗 CPU 资源
  • 现象:CPU 高负载但业务代码不复杂,系统整体变慢

2. 伪共享(False Sharing)

原理

CPU 缓存以 CacheLine(缓存行,64 字节) 为最小单位。

  • 多个独立变量落在同一个缓存行
  • 线程 A 修改变量 A,会导致同一行内变量 B 缓存失效
  • 线程 B 修改变量 B 也要重新刷缓存
  • 互不相关的变量互相干扰,频繁缓存失效,性能暴跌

场景

并发框架、计数器、批量统计、多线程高频读写独立变量。

解决

  • 缓存行填充:@sun.misc.Contended 注解(JDK1.8+)
  • 拆分对象、避免高频读写字段紧邻

3. GC 压力过大

高并发下高频问题:

  1. 瞬时流量大,创建大量短生命周期对象 → YoungGC 频繁
  2. 本地缓存、大集合、线程池堆积 → 对象老化,FullGC 频繁
  3. 并发容器 / 异步任务堆积 → 内存持续上涨,最终 OOM
  4. GC 停顿时间变长,接口抖动、超时

高并发 GC 典型诱因

  • 大量临时字符串、DTO、循环内创建对象
  • 无界队列、无限积压任务
  • ThreadLocal 不回收导致内存泄漏

二、线上排查工具 & 实战用法

1. jstack (最常用)

作用:查看线程快照、定位死锁、阻塞、死循环

1
jstack -l pid > thread.log

能排查什么

  1. 死锁:搜索 Found one Java-level deadlock
  2. 线程阻塞:大量 BLOCKED 等待锁
  3. 线程卡死:WAITING / TIMED_WAITING 堆积
  4. 无限循环:RUNNABLE 一直占用 CPU

2. jconsole

可视化 JDK 自带工具:

  • 线程状态监控、死锁检测
  • 堆内存、线程数、GC 趋势
  • 适合简单快速排查、本地 / 测试环境

3. Arthas(线上最强排查)

核心常用命令:

  1. thread:查看全部线程、CPU 占比、阻塞线程、死锁
  2. trace:追踪接口耗时,定位慢方法
  3. watch:监听方法入参 / 出参 / 异常
  4. gc:实时查看 GC 频率、堆内存
  5. dashboard:全局 CPU、内存、线程、负载面板

高并发必备:不用重启、不侵入代码,线上快速定位:

  • 锁等待、慢接口、死循环、内存泄漏、线程堆积

三、典型故障定位

1. 死锁

  • 现象:接口长期卡住、无报错、CPU 不高、线程大量 BLOCKED
  • 排查:jstack / arthas thread 直接检测循环锁依赖
  • 根源:互相持有对方锁、循环等待

2. 线程阻塞(非死锁)

  • 等待外部接口、数据库、redis、锁、Condition、park
  • 大量 WAITING 线程堆积
  • 线程池队列爆满、拒绝策略触发

3. CPU 飙高

  • 死循环、复杂计算、频繁序列化、频繁 GC
  • arthas thread -n 5 看 TOP CPU 线程

四、高并发性能优化核心思路

1. 减小锁粒度、降低锁竞争

  • 拆分大锁 → 细粒度锁
  • 读写分离:ReentrantReadWriteLock
  • 无锁优化:CAS、ThreadLocal、局部变量
  • 杜绝锁嵌套、缩短锁内代码执行时间

2. 合理线程池设计

  • 区分 IO 密集 / CPU 密集 配置线程数
  • 全部使用有界队列,限制最大线程,防 OOM
  • 自定义拒绝策略:告警 + 降级 + 任务落地
  • 异步任务指定独立线程池,避免公共池互相影响

3. 减少上下文切换

  • 控制线程总数,不要无限创建线程
  • 避免频繁短等待、频繁唤醒 / 阻塞
  • 业务合并、批量处理,减少线程交互

4. 内存 & GC 优化

  • 复用对象、池化思想(连接池、对象池)
  • 避免循环创建临时对象
  • 合理设置 JVM 参数:新生代大小、GC 收集器 (G1/ZGC)
  • 定时清理本地缓存、ThreadLocal.remove ()

5. 并发容器替代普通容器

  • ConcurrentHashMap 替代 HashMap
  • CopyOnWriteArrayList 读多写少场景
  • 阻塞队列解耦生产者消费者,削峰填谷

6. 异步 + 削峰 + 缓存

  • 核心接口多级缓存(本地缓存 + 分布式缓存)
  • 非核心逻辑异步化(CompletableFuture、MQ)
  • 限流、熔断、降级,保护核心服务
  • 批量聚合、合并请求,降低 QPS 压力

7. 规避底层坑

  • 解决伪共享、缓存行竞争
  • 避免大事务、长连接阻塞
  • 数据库 / 中间件连接池合理配置,防止连接耗尽

极简背诵总结

  1. 锁竞争:锁粒度过大、全局大锁 → 接口阻塞、吞吐低;

    上下文切换:线程过多、频繁阻塞唤醒 → CPU 损耗。

  2. 伪共享:多变量共用缓存行,互相缓存失效;用缓存行填充解决。

  3. GC 压力:短对象泛滥、无界积压、内存泄漏 → 频繁 GC、OOM。

  4. 排查工具:

    • jstack:线程快照、死锁;
    • jconsole:简易可视化监控;
    • Arthas:线上全能排查,定位慢方法、阻塞、CPU。
  5. 优化方向:

    减小锁粒度 + 合理线程池 + 异步削峰 + 缓存 + GC 优化 + 并发容器 + 限流降级。


高并发问题与排查
http://hanqichuan.com/2026/04/16/java并发/高并发问题与排查/
作者
韩启川
发布于
2026年4月16日
许可协议