一句话死锁就是两个线程互相等对方手里的锁形成​循环等待​。定位用jpsjstack两个命令预防靠固定加锁顺序和tryLock超时。什么是死锁线程A拿着锁1 → 想要锁2 → 等线程B释放锁2 线程B拿着锁2 → 想要锁1 → 等线程A释放锁1 A 等 B ────→ B 等 A ←──────────── 谁都不放手永远卡住。死锁的四个必要条件只要同时满足以下四个条件就会死锁条件含义打个比方互斥一把锁同一时刻只能被一个线程持有一个厕所一次只能一个人用持有并等待拿着一把锁的同时去等另一把锁占着厕所等钥匙钥匙在别人厕所里不可抢占​已持有的锁不能被强制剥夺不能把人从厕所里拽出来循环等待线程间形成环形等待链A 等 BB 等 A面试技巧记住​互持不可循​——互斥、持有并等待、不可抢占、循环等待。怎么定位死锁jps jstack第一步找到 Java 进程 ID$ jps-l12345com.example.YourApplication12346sun.tools.jps.Jps记下你要查的进程 ID比如12345。第二步打印线程快照$ jstack12345第三步看输出如果真的有死锁jstack 会​直接告诉你​​Found one Java-level deadlock: dispatch-thread-1: waiting to lock 0x000000076ab50080 (a java.lang.Object) which is held by dispatch-thread-2 dispatch-thread-2: waiting to lock 0x000000076ab500a0 (a java.lang.Object) which is held by dispatch-thread-1一眼就能看出thread-1 等 thread-2 手里的锁thread-2 等 thread-1 手里的锁——循环等待确认死锁。怎么预防和避免方案一固定加锁顺序预防死锁的根因是​加锁顺序不一致​。如果所有线程都按同一个顺序加锁就不会形成循环等待。// ❌ 危险两个方法加锁顺序不同voidtransferA(){synchronized(lock1){// 先锁1synchronized(lock2){...}// 再锁2}}voidtransferB(){synchronized(lock2){// 先锁2 ← 顺序反了synchronized(lock1){...}// 再锁1}}// transferA 和 transferB 并发调用 → 死锁// ✅ 安全统一加锁顺序voidtransferA(){synchronized(lock1){synchronized(lock2){...}}}voidtransferB(){synchronized(lock1){// 也先锁1synchronized(lock2){...}}}实践建议如果有多把锁约定一个全局的加锁顺序比如按锁的 hash 值排序所有方法都遵守。方案二tryLock 超时避免Locklock1newReentrantLock();Locklock2newReentrantLock();try{if(lock1.tryLock(100,TimeUnit.MILLISECONDS)){try{if(lock2.tryLock(100,TimeUnit.MILLISECONDS)){try{// 两把锁都拿到了执行业务}finally{lock2.unlock();}}else{// 拿不到 lock2放弃别卡死System.out.println(获取 lock2 超时回滚);}}finally{lock1.unlock();}}}catch(InterruptedExceptione){Thread.currentThread().interrupt();}等不到就放弃不会卡死。这是ReentrantLock相比synchronized的优势之一。其他排查手段工具用途说明jstack线程快照JDK 自带最常用jconsole可视化监控JDK 自带 GUI 工具VisualVM线程分析可以看线程状态和锁信息Arthas在线诊断阿里开源thread -b直接检测死锁JDK Flight Recorder性能分析JDK11 自带可录制线程事件Arthas 的thread -b命令非常实用——找到当前阻塞其他线程的那个罪魁祸首线程直接告诉你谁卡住了谁。 面试回答模板死锁是两个线程互相等待对方持有的锁形成循环等待。 产生死锁需要四个条件同时满足互斥、持有并等待、不可抢占、循环等待。 定位的话用 jps 找到 Java 进程 ID然后 jstack 打印线程快照 输出中会直接标注 Found one Java-level deadlock 告诉你哪个线程等哪个锁、被哪个线程持有一眼就能看出来。 线上也可以用 Arthas 的 thread -b 命令快速检测。 预防分两种 第一种是固定加锁顺序所有线程按统一的顺序获取锁避免循环等待 第二种是用 ReentrantLock 的 tryLock 设置超时等不到锁就放弃不会卡死。参考来源JDK 工具文档jstack、jps《Java 并发编程的艺术》第 5 章Arthas 官方文档thread 命令