死锁发生的四个必要条件是互斥、持有并等待、不可剥夺和循环等待,必须同时满足;实践中最常用的是统一加锁顺序来破坏循环等待。

Java 并发编程中死锁发生的四个必要条件必须**同时满足**,缺一不可。只要打破其中任意一个,死锁就不会发生。
互斥条件
资源(如对象锁)具有排他性,同一时刻只能被一个线程持有。例如,synchronized(lock) 或 ReentrantLock.lock() 都是互斥的——其他线程必须等待当前线程释放锁后才能进入。这个条件通常无法消除,因为“竞争资源”本身就意味着需要互斥访问。
持有并等待条件
一个线程已经持有一个或多个锁,同时又去申请新的锁,且在等待新锁期间不释放已持有的锁。比如线程 A 拿着 lockA,接着尝试获取 lockB;此时若 lockB 被线程 B 占着,A 就会阻塞,但 lockA 仍牢牢握在手里。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
不可剥夺条件
Java 中的锁不能被强制剥夺。也就是说,线程 A 持有锁后,其他线程无法强行把它抢走;只有 A 主动退出同步块、调用 unlock() 或异常退出(且正确处理),锁才会释放。这点和操作系统中可抢占式资源不同,是 Java 死锁容易形成的关键因素之一。
循环等待条件
多个线程之间形成闭环等待关系。典型例子是:线程 A 等待线程 B 持有的锁,线程 B 又等待线程 A 持有的锁,构成“A→B→A”的环。更长的链如 A→B→C→A 同样成立。只要等待图中存在环路,且每个节点都对应一个独占锁,就满足这一条件。
这四个条件就像四把锁扣在一起的链条,解开任何一环,死锁就解体了。实际开发中,最常用、最可控的破局方式是**统一加锁顺序**(破坏循环等待),比如所有转账操作都按账户 ID 升序先锁小号再锁大号。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










