十八 死锁及定位
2018-11-26 本文已影响0人
BeYearn
- 死锁是一种特定的程序状态,在实体之间,由于循环依赖导致彼此一直处于等待之中,没有任何个体可以继续前进
- 定位死锁最常见的方式就是利用*** jstack*** 等工具获取线程栈,然后定位互相之间的依赖关系,进而找到死锁。如果是比较明显的死锁,往往 jstack 等就能直接定位,类似 JConsole 甚至可以在图形界面进行有限的死锁检测。
-
可以使用java的jps命令(或系统的ps命令, 任务管理器等工具)确定进程id
图片.png
然后使用java的jstack命令: jstack 进程id
图片.png
- 避免死锁的一些方法
-
如果可能的话,尽量避免使用多个锁,并且只有需要时才持有锁。否则,即使是非常精通并发编程的工程师,也难免会掉进坑里,嵌套的 synchronized 或者 lock 非常容易出问题。
-
如果必须使用多个锁,尽量设计好锁的获取顺序(顺序获取). 这个说起来简单,做起来可不容易,参看著名的[银行家算法]
-
使用带超时的方法,为程序带来更多可控性。
类似 Object.wait(…) 或者 CountDownLatch.await(…),都支持所谓的 timed_wait,我们完全可以就不假定该锁一定会获得,指定超时时间,并为无法得到锁时准备退出逻辑。
并发 Lock 实现,如 ReentrantLock 还支持非阻塞式的获取锁操作 tryLock(),这是一个插队行为(barging),并不在乎等待的公平性,如果执行时对象恰好没有被独占,则直接获取锁。有时,我们希望条件允许就尝试插队,不然就按照现有公平性规则等待,一般采用下面的方法:
if (lock.tryLock() || lock.tryLock(timeout, unit)) {
// ...
}
- 有时并不是因为阻塞导致的死锁, 而是某个线程进入了死循环, 其它线程一直在等待, 诊断该情况: 当是死循环引起的其他线程阻塞,会导致cpu飙升, 可以通过linux下top命令查看cpu使用率较高的java进程,进而用top -Hp ➕pid查看该java进程下cpu使用率较高的线程。再用jstack命令查看线程具体调用情况,排查问题。