synchronized 本身不导致死锁,关键在锁的使用方式;应避免嵌套锁、统一获取顺序、慎用可重入性、优先选用 reentrantlock 或无锁方案。

synchronized 在多线程中容易引发死锁,核心问题不在 synchronized 本身,而在于锁的使用方式——尤其是多把锁的获取顺序和嵌套结构。只要控制好锁的粒度、顺序和范围,就能大幅降低风险。
避免嵌套锁结构
嵌套 synchronized 块(比如在外层锁内再进另一个 synchronized)是死锁高发区,尤其当不同线程以不同顺序进入嵌套时。这不是语法错误,但逻辑上极易形成“你等我、我等你”的循环等待。
- 尽量用单层锁:一个临界区只用一个 synchronized 块包裹,不层层嵌套
- 若必须保护多个资源,优先考虑合并操作或重构为原子方法,而非靠嵌套加锁来“保险”
- 避免在 synchronized 块里调用外部方法——除非能 100% 确认该方法不会尝试获取其他锁
统一锁获取顺序
多个线程竞争多把锁时,只要保证所有线程都按相同顺序申请锁,就能打破“循环等待”这一死锁必要条件。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 给锁对象定义明确的优先级,例如按对象哈希值排序:
if (System.identityHashCode(lockA) - 或用常量标识锁序:定义
public static final int LOCK_ORDER_ACCOUNT = 1;等,让业务逻辑按序号升序加锁 - 禁止出现“线程1:lockA → lockB”,而“线程2:lockB → lockA”这类反向路径
慎用可重入性,别把它当万能解
synchronized 是可重入锁,同一线程重复进入同一把锁不会阻塞,但这不等于鼓励嵌套。可重入解决的是“自己锁自己”的问题,不是“多资源协同”的方案。
- 不要因为“能重入”就随意在方法内部再加一层 synchronized(this),容易掩盖设计缺陷
- 实例方法加 synchronized 锁的是 this;静态方法锁的是 Class 对象——两者互不干扰,但混用时要清楚锁目标是否真的一致
- 锁对象尽量私有且不可变(如
private final Object lock = new Object();),避免被外部误用或共享
用超时与替代方案兜底
synchronized 不支持超时,一旦卡住就是永久等待。生产环境建议关键路径改用更可控的机制。
- 对需多锁协调的场景,优先选用
ReentrantLock配合tryLock(long, TimeUnit),超时后主动释放已持锁并回退 - 对简单计数、状态更新等,考虑无锁方案:如
AtomicInteger、ConcurrentHashMap,绕过锁竞争 - 借助工具提前发现隐患:用
jstack <pid></pid>查看线程堆栈,识别 BLOCKED 状态及锁等待链
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










