两个或多个线程之间,由于互相持有对方需要的锁,而永久处于阻塞的状态。
定位死锁:
最常见的方式就是利用 jstack 等工具获取线程栈,然后定位互相之间的依赖关系,进而找到死锁。如果是比较明显的死锁,往往 jstack 等就能直接定位:首先,可以使用 jps 或者系统的 ps 命令、任务管理器等工具,确定进程 ID。其次,调用 jstack 获取线程栈,找到处于 BLOCKED 状态的线程
Java 提供的标准管理 API,ThreadMXBean,其直接就提供了 findDeadlockedThreads() 方法用于定位。线程进行快照本身是一个相对重量级的操作,还是要慎重选择频度和时机。
类加载过程发生的死锁,尤其是在框架大量使用自定义类加载时,Java 有官方文档进行了详细解释,并针对特定情况提供了相应 JVM 参数和基本原则。
如何在编程中尽量预防死锁呢?
1)尽量避免使用多个锁,并且只有需要时才持有锁。
2)如果必须使用多个锁,尽量设计好锁的获取顺序
3)使用带超时的方法,为程序带来更多可控性。类似 Object.wait(…) 或者 CountDownLatch.await(…),都支持所谓的 timed_wait
4)静态代码分析(如 FindBugs)
有时候并不是阻塞导致的死锁,只是某个线程进入了死循环,导致其他线程一直等待,这种问题如何诊断呢?
答:可以通过linux下top命令查看cpu使用率较高的java进程,进而用top -Hp ➕pid查看该java进程下cpu使用率较高的线程。再用jstack命令查看线程具体调用情况,排查问题。