优化 synchronized 锁粒度的核心是缩小锁范围、专一锁对象,避免全局大锁;用同步代码块替代同步方法,选择细粒度锁对象,禁用锁内耗时操作,并结合jvm优化与并发工具类提升性能。

优化 synchronized 的锁粒度,核心是让锁的范围尽可能小、对象尽可能专一,避免“一把大锁管全局”带来的线程阻塞和性能浪费。
用同步代码块代替同步方法
同步方法会把整个方法体作为临界区,锁住的是 this 或 Class,往往包含非共享资源操作或耗时逻辑(如日志、IO),导致其他线程无谓等待。
- 把锁精准圈在真正需要保护的共享变量读写处,比如只包裹 count++ 或 map.put(key, value)
- 示例:把
public synchronized void add() { log.info("start"); count++; log.info("end"); }改为public void add() { log.info("start"); synchronized(this) { count++; } log.info("end"); }
选择更细粒度的锁对象
避免直接锁 this 或 Class,改用与业务逻辑强绑定、作用域更小的对象。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 对集合类操作,可用
private final Object mapLock = new Object();作为锁,而不是锁整个对象实例 - 银行转账场景中,不锁整个 Account 类或两个账户实例,而是按
Math.min(from.hashCode(), to.hashCode())确定唯一顺序,分别锁两个账户——既保证线程安全,又允许不同账户对之间并发执行 - 静态资源隔离时,可用
private static final Object COUNTER_LOCK = new Object();替代static synchronized,避免锁整个 Class
避免锁内做耗时或阻塞操作
锁持有时间越长,竞争越激烈,轻量级锁容易升级为重量级锁,性能断崖式下降。
- 禁止在 synchronized 块里调用远程接口、数据库查询、文件读写、sleep 等
- 可先在锁外准备数据(如校验参数、计算结果),再进锁完成原子更新
- 例如库存扣减:先查缓存判断是否足够 → 锁住库存对象 → 扣减并更新 → 解锁 → 再发消息通知
结合锁优化机制与替代方案
JVM 和 JDK 已提供自动优化能力,但需合理配合使用习惯。
- 确认偏向锁是否启用(默认开启):它对单线程反复进入同一同步块极友好;若确定是多线程高频竞争场景,可考虑
-XX:-UseBiasedLocking关闭以减少撤销开销 - 循环内避免重复加锁:不要写
for (...) { synchronized(lock) { ... } },应把整个循环体或关键段整体包裹 - 当锁粒度已足够细但仍存在瓶颈时,可评估迁移到
java.util.concurrent工具类,如AtomicInteger替代计数器锁、ConcurrentHashMap替代手动同步 HashMap
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










