死锁经常被大厂考察,而且实际的开发中,会造成很重要的问题,下面我就来全面详解死锁的原因以及解决办法@mikechen
死锁是什么
死锁是计算机科学、和操作系统领域中一个经典且复杂的问题,它发生在多个进程、或线程因争夺资源而陷入无限等待的状态。
若无外力介入,这些进程将无法继续执行,这就会出现死锁。
多线程死锁
死锁在多线程编程中尤其常见,比如使用互斥锁(mutex)时未正确释放。
比如:一组(两个或多个)线程,因争夺资源(比如:库存),而陷入一种互相等待的僵持状态,导致它们都无法继续执行下去。
如下所示:
Thread A: lock(lock1) → lock(lock2) Thread B: lock(lock2) → lock(lock1)
两个线程互相等待对方释放锁,形成死锁。
数据库死锁
再比如:数据库事务,也是经常发生死锁的地方。
如下所示:
-- 事务 A: BEGIN; UPDATE accounts SET balance = balance - 100 WHERE id = 1; -- 等待 row 2 -- 事务 B: BEGIN; UPDATE accounts SET balance = balance + 100 WHERE id = 2; -- 等待 row 1
事务 A 锁定表 row1,等待 row2,事务 B 锁定 row2,等待 row1,互相阻塞,这样也会出现死锁。
如何解决死锁?
死锁:通常是因为线程以不同顺序请求多个锁,造成“循环等待”。
所以,要解决死锁,需要确保所有线程/模块按相同顺序请求资源,破坏“循环等待”条件。
如下所示:
class A {} class B {} final A a = new A(); final B b = new B(); Thread t1 = new Thread(() -> { synchronized (a) { synchronized (b) { System.out.println("Thread 1 acquired A then B"); } } }); Thread t2 = new Thread(() -> { synchronized (a) { // 先锁 A,再锁 B(保持一致) synchronized (b) { System.out.println("Thread 2 acquired A then B"); } } });
统一加锁顺序,所有线程获取资源时,遵循同样的顺序。
以及,使用 ReentrantLock
提供的 tryLock()
方法设置超时,避免无限等待。
Lock lock1 = new ReentrantLock(); Lock lock2 = new ReentrantLock(); Thread t1 = () -> { try { if (lock1.tryLock(1, TimeUnit.SECONDS)) { try { if (lock2.tryLock(1, TimeUnit.SECONDS)) { try { // critical section } finally { lock2.unlock(); } } } finally { lock1.unlock(); } } } catch (InterruptedException e) { e.printStackTrace(); } };
数据库死锁解决
如果死锁发生在数据库事务中,解决方法如下:
确保事务按照相同顺序访问资源,破坏“循环等待”条件。
如下所示:
-- 不推荐(死锁风险大): T1: UPDATE A ...; UPDATE B ...; T2: UPDATE B ...; UPDATE A ...; -- 推荐(统一顺序): T1, T2: UPDATE A ...; UPDATE B ...;
以及,减少事务粒度,拆分长事务。
如下所示:
-- 第一个事务:更新账户余额 START TRANSACTION; UPDATE account SET balance = balance - 100 WHERE account_id = 1; COMMIT; -- 第二个事务:更新另一账户余额 START TRANSACTION; UPDATE account SET balance = balance + 100 WHERE account_id = 2; COMMIT; -- 第三个事务:更新交易日志 START TRANSACTION; UPDATE transaction_log SET status = 'completed' WHERE transaction_id = 123; COMMIT;
每个事务只处理一个简单的更新操作,锁持有时间较短,减少了死锁的概率。
mikechen
mikechen睿哥,10年+大厂架构经验,资深技术专家,就职于阿里巴巴、淘宝、百度等一线互联网大厂。
关注「mikechen」公众号,获取更多技术干货!

后台回复【架构】即可获取《阿里架构师进阶专题全部合集》,后台回复【面试】即可获取《史上最全阿里Java面试题总结》