JFR捕获锁竞争需显式启用jdk.JavaMonitorEnter和jdk.JavaMonitorPark事件,推荐用jcmd动态开启并配合自定义配置文件过滤,避免默认profile未启用锁事件;事件duration超1ms即需警惕,超5ms属高延迟瓶颈,monitorObject地址一致表明争同一把锁。

怎么用JFR捕获锁竞争事件
直接启用 jdk.JavaMonitorEnter 和 jdk.JavaMonitorPark 这两个事件,就能拿到锁竞争的原始证据。它们分别对应“尝试进入 synchronized 块”和“因抢不到锁而挂起”的动作,不是推测,是 JVM 内核级记录的真实行为。
推荐用 jcmd 动态开启,避免重启应用:
jcmdJFR.start name=lockrec settings=profile delay=0s duration=60s settings=/path/to/lock-filter.jfc - 其中
lock-filter.jfc是自定义配置文件,只启用锁相关事件,减少干扰(否则默认 profile 会录大量 GC/IO 事件) - 若没准备配置文件,可用内置 profile:但务必加
settings=profile,再手动过滤——因为默认 profile 不开jdk.JavaMonitorEnter
注意:jdk.MonitorEnter 是旧名(JDK 8),OpenJDK 11+ 必须用 jdk.JavaMonitorEnter,写错就收不到任何锁事件。
怎么看JFR里锁等待是否严重
导出 .jfr 文件后,用 jfr print --events jdk.JavaMonitorEnter,jdk.JavaMonitorPark myapp.jfr 提取原始事件流,重点看三列:
-
duration:值 > 1ms 就值得警惕;> 5ms 属于高延迟锁等待,大概率是瓶颈 -
stackTrace:确认是不是业务关键路径(比如在订单处理循环里反复抢同一个ConcurrentHashMap的 segment 锁) -
monitorClass或monitorObject:多个线程的monitorObject地址一致,说明真正在争同一把锁
别只盯平均值——用 jfr 命令加 --json 输出后,用 jq 统计分布:jfr print --json myapp.jfr | jq -r '.events[] | select(.type == "jdk.JavaMonitorEnter") | .duration' | sort -n | tail -20,看 P95/P99 等待时长。
为什么jstack看到“waiting to lock”但JFR没记录
常见原因就两个:
- JFR 没真正启用锁事件:检查
jcmd输出,确认JFR.check jdk.JavaMonitorEnter状态是enabled而非disabled;很多用户误以为加了-XX:+FlightRecorder就自动开锁监控,其实必须显式 enable - 锁被内联优化绕过:JIT 编译器对无竞争的 synchronized 块做锁消除(Lock Elision),此时根本不会触发 monitor-enter 事件;这种情况下
jstack也看不到 “waiting to lock”,所以如果 jstack 有阻塞但 JFR 无事件,先怀疑是不是锁已被 JIT 优化掉(可加-XX:-EliminateLocks临时禁用验证)
另外,ReentrantLock.lock() 不走 monitor 机制,JFR 默认不捕获——得靠 jdk.JavaThreadPark + 堆栈里找 AbstractQueuedSynchronizer 调用链来间接推断。
线上长期开着JFR会不会拖慢服务
只要不用 method-sampling 或高频堆栈采集,纯锁事件开销极低:OpenJDK 17+ 中,jdk.JavaMonitorEnter 单次事件平均耗时
- 生产环境建议配置
maxSize=200MB+maxAge=1h,防止磁盘写满 - 绝对不要用
settings=default长期开——它包含高频方法采样,CPU 开销可能飙升 5%~10% - 真正安全的长期方案:用
settings=profile+ 自定义 jfc 只开jdk.JavaMonitorEnter/jdk.JavaMonitorPark/jdk.ThreadPark,实测 CPU 影响
最易被忽略的一点:JFR 录制本身不会导致 STW,但导出 .jfr 文件时(jcmd JFR.dump)会短暂暂停所有 Java 线程——所以别在流量高峰执行 dump,优先用 dumpOnExit=true 让进程退出时自动落盘。











