线程池加到 48 个线程,CPU 只用了 15%,接口吞吐没涨,jstack 里 40 个线程状态是 BLOCKED,都在等同一个对象监视器。乍看像缓存或者权限的锅,追下去往往不是。

jstack 1 | grep -A 5 'BLOCKED' | head -30
pidstat -u -p 1 1 3

追下去是这么回事:任务里访问了一个共享的统计对象,方法上加了 synchronized,所有线程串行通过。线程再多也只是在锁队列里排着。

「池内锁竞争」这个问题文档写得含糊,实际行为以当前版本为准,别照旧版本的结论套。验证用真实数据走一遍,测试数据太干净,边界情况根本碰不到。

能分两步做的操作就别合成一步,中间看一眼返回值,出问题好判断。报错里带路径的,先去看那个路径在不在、权限对不对。

同一份配置存在多处的,先确认改的是被加载的那一份。

具体做法是,先看 jstack 里 BLOCKED 的锁地址是否同一个;把共享计数换成 LongAdder 或原子类;必须同步的段落缩小到最小范围;压测对比改前改后的吞吐和 BLOCKED 线程数。

验收就看一点,BLOCKED 线程数降到个位数,同样并发下吞吐提升 3 倍以上。

作者 9823189