synchronized代码块应精准锁定临界区,优先使用私有final对象作锁,避免this或Class.class;只包裹共享状态操作,移出IO等耗时逻辑;按业务维度分拆锁,防范死锁与锁膨胀。

使用 synchronized 代码块可以只锁定真正需要同步的代码段,避免整个方法被锁住,从而减小锁的粒度、提升并发性能。
明确锁对象,避免使用 this 或 Class.class
锁对象的选择直接影响锁的范围。用 this 或 XXX.class 容易造成过度竞争——前者让所有实例方法串行执行,后者让整个类的所有静态同步操作互斥。
- 优先使用私有 final 对象作为锁,例如:
private final Object lock = new Object(); - 若需保护某个字段(如 list),可用该字段本身(前提是它不会被外部替换)或专门创建的锁对象
- 避免锁对象被 public 方法返回或被修改,否则可能破坏同步契约
只包裹临界区,不包含无关逻辑
把耗时操作、IO、网络调用等非共享资源访问代码移出 synchronized 块,否则会白白拖长持有锁的时间。
- 错误示例:在 synchronized 块里查数据库、解析 JSON、调用远程接口
- 正确做法:先获取必要参数 → 进入同步块更新共享状态 → 退出后处理后续逻辑
- 例如:缓存更新时,仅同步“判断是否存在 + 写入 map”这两步,而不是整个加载+缓存流程
按业务维度拆分锁,避免单一大锁
当多个独立资源共用一个锁时,它们会相互阻塞。可为不同资源分配不同锁对象,实现细粒度隔离。
立即学习“Java免费学习笔记(深入)”;
- 比如用户订单系统中,订单 A 和订单 B 的状态更新互不影响,可用
orderLocks.get(orderId)获取专属锁 - 使用
ConcurrentHashMap配合computeIfAbsent动态创建锁对象,注意控制锁对象数量防止内存泄漏 - 慎用字符串或用户输入作为锁对象(存在 intern 冲突或安全风险),推荐用
new Object()或封装后的 key 对象
注意锁升级与死锁风险
细粒度锁虽好,但引入多个锁后容易引发死锁,且 JVM 在高竞争下可能触发锁膨胀(偏向锁 → 轻量级锁 → 重量级锁)。
- 多个锁嵌套时,始终按固定顺序加锁(如按 id 升序)
- 避免在同步块内调用外部可重入方法,尤其是可能间接获取其他锁的第三方代码
- 可通过 JStack 或 JConsole 观察线程阻塞情况,验证锁粒度优化是否生效


















