在 synchronized 块内结合 metrics 做高并发监控,核心是不干扰锁语义,仅在关键路径安全采集指标:用 static final timer 记录整个临界区耗时,counter 分层统计等待/进入/错误,gauge 动态暴露活跃持有线程数,并避免块内重操作。

在 synchronized 块内结合 Metrics(如 Micrometer 或 Dropwizard Metrics)做高并发监控,核心思路是:**不干扰锁的语义,只在关键路径上安全地记录指标**。synchronized 本身不支持嵌套监控钩子,但可以借助 Metrics 提供的计时器(Timer)、计数器(Counter)和仪表(Gauge)在加锁前后或内部做轻量采集。
用 Timer 精确统计同步块执行耗时
Timer 是最常用且推荐的方式,它能自动记录调用次数、延迟分布(P50/P95/P99)、速率等。关键点是确保 Timer.record() 调用本身不引入额外锁竞争或异常中断逻辑。
- Timer 实例应为 static final,避免重复创建和内存开销
- record() 是线程安全的,可直接在 synchronized 块内调用,无需额外同步
- 建议包裹整个临界区(含锁获取到退出),真实反映“排队+执行”总耗时
private static final Timer criticalSectionTimer = Timer.builder("app.locked.operation")
.description("Time spent in synchronized critical section")
.register(Metrics.globalRegistry);
public void doCriticalWork(String key) {
synchronized (lockMap.computeIfAbsent(key, k -> new Object())) {
criticalSectionTimer.record(() -> {
// 实际业务逻辑:DB 查询、缓存更新、状态变更等
updateCache(key);
writeToDB(key);
});
}
}
用 Counter 区分锁等待与执行成功/失败
单纯看耗时不够,还需知道有多少请求被阻塞、多少执行出错。可在 synchronized 块外/内分层打点:
- 在进入 synchronized 前 increment "lock.wait.count" —— 反映竞争强度
- 在 synchronized 块内 increment "lock.enter.count" —— 表示成功获得锁
- 捕获异常后 increment "lock.error.count" —— 定位不稳定源头
用 Gauge 动态暴露当前持有锁的线程数(进阶)
如果想实时观测“有多少线程正在该锁上执行”,可用 Gauge 绑定一个原子整数:
- 定义 private static final AtomicInteger activeLockHolders = new AtomicInteger(0)
- 在 synchronized 块开头 activeLockHolders.incrementAndGet()
- 在 finally 块中 activeLockHolders.decrementAndGet()
- 通过 Gauge.builder(...).bindTo(registry) 关联该值
避坑提醒:别在 synchronized 块里做重操作
Metric 上报本身极轻量,但以下行为会破坏监控可信度或引发问题:
- 不要在 synchronized 块里调用 registry.remove() 或重新注册 metric —— 非线程安全且无必要
- 避免在块内触发日志打印(尤其是 debug/info 级别)、HTTP 调用、磁盘写入 —— 这会放大锁粒度,让监控数据失真
- 不要用 synchronized(this) + Timer.record() 套 Timer.record() —— 不仅冗余,还可能因异常导致 record() 未执行
Metrics 的价值在于反映真实瓶颈,而不是给瓶颈添砖加瓦。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











