选对锁对象是避免死锁的第一道防线。应优先使用私有final对象作锁,避免this、XXX.class、字符串等危险锁对象;按业务维度拆分锁,多锁场景下统一按哈希值顺序获取;禁止在synchronized块内调用外部不可控代码。

选对锁对象是避免死锁的第一道防线。关键不是“能不能锁”,而是“锁得准不准、范围窄不窄、顺序稳不稳”。
优先用私有 final 对象作锁
这是最安全、最可控的方式。
- 声明为 private final Object lock = new Object();,外部无法访问或替换,杜绝锁被意外共享
- 避免使用 this:会导致整个实例所有同步方法/块串行,不同业务逻辑互相干扰
- 避免使用 XXX.class:静态同步锁全局唯一,类内所有静态同步操作强互斥,极易引发高竞争和死锁风险
- 慎用字符串或用户输入值(如
"key1")作锁:可能因字符串常量池(intern)导致本不该关联的线程意外共用同一把锁
按业务维度拆分锁对象
多个资源之间若无状态耦合,就别共用一把锁。
- 例如订单系统中,订单 A 和订单 B 的状态更新互不影响,可用
ConcurrentHashMap.computeIfAbsent(orderId, k -> new Object())动态生成专属锁 - 注意控制锁对象数量,避免内存泄漏;可配合弱引用或定时清理策略
- 字段本身可作锁的前提是它不会被外部替换(如
private final List<T> items = new ArrayList<>();),否则锁语义会失效
多锁场景下必须统一获取顺序
只要涉及两个及以上锁,顺序就是生死线。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
- 不要依赖业务字段名或硬编码顺序(如“先锁账户A再锁账户B”),容易随需求变更而错乱
- 推荐用 System.identityHashCode() 计算锁对象哈希值,始终先获取哈希值小的锁,再获取大的
- 封装加锁逻辑到工具方法中,确保所有调用路径都走同一套顺序规则
避免在 synchronized 块内调用不可控外部代码
看似没加新锁,实则可能间接触发另一把锁。
- 禁止在同步块里调用第三方服务、数据库操作、日志框架(某些实现含锁)、或未审查的回调函数
- 警惕
toString()、equals()等隐式方法——若它们内部又用了别的锁,就埋下嵌套死锁隐患 - 正确做法:提前读取必要数据 → 进入同步块仅做状态变更 → 退出后处理副作用(IO、通知、计算等)
不复杂但容易忽略:锁对象选择不是语法问题,而是并发契约的设计起点。选得准,后续加锁逻辑才不会失控。

















