一、什么是死锁?
死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象。若无外力作用,这些进程都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁。这些永远在互相等待的进程称为死锁进程。
二、死锁形成条件
- 互斥条件:线程对已经获取到的资源进行排他性使用,即该资源同时只有一个线程占用,如果此时还有其他线程请求获取该资源,则必须等待,直到占用资源的线程释放。
- 请求并持有条件:一个线程已经持有了至少一个资源,但又请求了新的资源,而新的资源已经被其他线程占用,所以当前线程会被阻塞,但并不释放自己已经获取的资源。
- 不可剥夺条件:线程获取到的资源在使用完之间不会被其他线程所抢占,只能自己释放。
- 环路等待:必然存在一个环形链,T0等T1,T1等T0。
三、如何避免死锁
理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以最大可能地避免、预防和解除死锁。只要打破四个必要条件之一就能有效预防死锁的发生: - 打破互斥条件:改造独占性资源为虚拟资源,大部分资源已无法改造。
- 打破不可抢占条件:当一进程占有一独占性资源后又申请一独占性资源而无法满足,则退出原占有的资源。
- 避免资源独占:尽量避免一个进程获取了某些资源后再次请求其他资源。而应该将所有资源一次性申请到位。
- 避免资源互斥:有些资源同一时间只能被一个进程战局,比如打印机,需要采用一些手段避免资源互斥的问题。
- 减少资源持有和等待:当一个进程持球一些资源并且等待一些资源的时候,其他进程就无法使用这些资源。所以尽量减少资源的持有和等待。
- 采用资源剥夺策略:当一个进程请求的资源被另外的资源占用的时候,可以采用资源剥夺的策略。即暂停占用该进程的策略:直到该资源被释放。
- 采用进程抢占策略:当一个进程等待时间过长,可以采用资源抢占的策略,即强制中断执行中的进程。强行释放其占用的资源。
四、如何排查死锁
Jstack是Java虚拟机自带的一种堆栈跟踪工具,用于打印出给定的java进程ID或core file或远程调试服务的Java堆栈信息。Jstack工具可以用于生成java虚拟机当前时刻的线程快照。线程快照是当前java虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。线程出现停顿的时候通过jstack来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。
JConsole工具是JDK自带的监控工具,在JDK/bin目录下可以找到。它用于连接正在运行的本地或者远程的JVM,对运行在Java应用程序的资源消耗和性能进行监控,并画出大量的图表,提供强大的可视化界面。而且本身占用的服务器内存很小,甚至可以说几乎不消耗。
五、小结
死锁是多进程并发执行中的一种常见问题,它可以被解释为若干进程因为彼此竞争系统资源而导致陷入互相等待的一种僵局状态。为了避免死锁的发生,我们需要明确死锁发生的四个必要条件:互斥条件、不可抢占条件、请求与保持条件以及循环等待条件,并采取相应的策略和措施来破坏这些条件。其中的一些策略和措施包括:破坏互斥条件、破坏不可抢占条件、破坏请求与保持条件、破坏循环等待条件以及合理地设置超时时间。通过综合运用这些策略和措施,我们可以有效地避免死锁的发生,从而保障系统的稳定性和可靠性。