java如何解决死锁
死锁的定义与条件
死锁指多个线程因争夺资源而陷入互相等待的状态,无法继续执行。产生死锁需满足四个条件:
- 互斥条件:资源一次仅能被一个线程占用。
- 占有并等待:线程持有资源的同时请求其他资源。
- 非抢占条件:已分配的资源不可被强制剥夺。
- 循环等待:多个线程形成环形等待链。
死锁检测与诊断
通过工具分析线程转储(Thread Dump)或使用可视化工具定位死锁:
// 获取线程转储
ThreadMXBean bean = ManagementFactory.getThreadMXBean();
long[] threadIds = bean.findDeadlockedThreads();
if (threadIds != null) {
ThreadInfo[] infos = bean.getThreadInfo(threadIds);
for (ThreadInfo info : infos) {
System.out.println(info.getThreadName());
}
}
死锁预防策略
破坏占有并等待
- 一次性申请所有资源,若无法满足则释放已持有资源。
synchronized (lock1) { synchronized (lock2) { // 业务逻辑 } }
破坏非抢占条件
- 使用
ReentrantLock.tryLock()尝试获取锁,超时失败后释放资源。Lock lock1 = new ReentrantLock(); Lock lock2 = new ReentrantLock(); if (lock1.tryLock(100, TimeUnit.MILLISECONDS)) { try { if (lock2.tryLock(100, TimeUnit.MILLISECONDS)) { try { /* 业务逻辑 */ } finally { lock2.unlock(); } } } finally { lock1.unlock(); } }
破坏循环等待
- 定义全局资源申请顺序,避免环形依赖。例如强制按
lock1 -> lock2顺序加锁。
死锁避免与恢复
银行家算法
- 分配资源前检查系统是否处于安全状态,避免进入死锁。
定时锁检测
- 周期性检查死锁,若检测到则中断线程或回滚操作。
实际应用建议
- 使用
java.util.concurrent高阶工具(如CountDownLatch、CyclicBarrier)替代显式锁。 - 限制锁的作用域与持有时间,避免嵌套锁。
- 监控工具推荐:VisualVM、JConsole、Arthas。
通过合理设计资源申请顺序、引入超时机制及工具分析,可有效减少死锁风险。







