Java中应缩小synchronized锁范围,仅保护真正需要互斥的临界区;明确使用私有final锁对象,避免this或常量池对象;按业务拆分独立锁;注意同步块的可见性边界与volatile配合。

在 Java 中,使用 synchronized 同步代码块缩小锁范围,核心是只对真正需要互斥访问的临界区加锁,而不是锁住整个方法或大段逻辑。这样能显著提升并发性能,减少线程等待时间。
明确锁对象,避免锁粒度过粗
同步代码块必须指定一个具体的锁对象(如某个成员变量、私有 final 对象),而不是随意用 this 或类对象,否则容易导致意外的锁竞争。
- 优先使用私有且不可变的锁对象,例如:private final Object lock = new Object();
- 避免用
this作锁——外部代码可能也 synchronized(this),引发非预期的串行化 - 不要用字符串字面量或 Integer 等常量池对象作锁,它们可能被其他地方复用
只包裹真正共享且需原子操作的代码段
把锁范围严格限制在读写共享变量、修改共享状态、调用非线程安全方法等必要位置,其余计算、IO、日志等移出同步块。
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
- 错误示例(锁了不该锁的部分):
synchronized(lock) {
int a = computeX(); // 不依赖共享状态,可移出
log.info("start"); // 日志不涉及共享数据,可移出
sharedCounter++; // 只有这行需要保护
} - 正确写法:
int a = computeX();
log.info("start");
synchronized(lock) {
sharedCounter++;
}
按业务逻辑拆分独立锁,避免“一把锁管所有”
当多个共享资源彼此无关时,应为每个资源分配独立锁对象,实现细粒度并发控制。
立即学习“Java免费学习笔记(深入)”;
- 例如:一个类管理用户余额和订单数两个字段,可分别定义:
private final Object balanceLock = new Object();
private final Object orderCountLock = new Object(); - 更新余额时只 synchronized(balanceLock),更新订单数时只 synchronized(orderCountLock),二者互不阻塞
- 切忌共用同一个锁对象,除非这些操作本身存在强一致性要求(如“扣款+生成订单”必须原子)
注意锁升级与可见性边界
同步代码块不仅保证互斥,还确保进入前读取最新值、退出时刷新到主内存。但这个效果仅作用于该块内——所以非同步代码无法自动获得最新值。
- 如果某变量只在同步块中读写,那它对外部的可见性由 synchronized 保障,无需额外 volatile
- 但如果部分读操作在同步块外(比如缓存结果),又没做同步或 volatile 声明,则可能看到过期值
- 建议:对多线程共享的基本状态变量,要么统一用同一把锁保护读写,要么声明为 volatile(仅适用于简单读写无依赖场景)

















