Java死锁检测以及解决办法

Java死锁检测以及解决办法

Java死锁检测以及解决办法

一、死锁概念

1. 什么是死锁?

两个或者多个线程互相持有对方所需要的资源, 都在等待对方执行完毕才能继续往下执行的时候,就称为发生了死锁。结果就是两个线程或多个线程都陷入了无限的等待中。由于线程被无限期地阻塞,因此程序不可能正常终止。

一般是有多个锁对象的情况下并且获得锁顺序不一致造成的。

2. java 死锁产生的四个必要条件

1) 互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用

2)不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。

3)请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占有。

4)循环等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路。

3. 死锁的影响

1)系统资源浪费

一旦发生死锁,相关的进程会无限期地占用系统资源,而这些资源无法被其他进程使用,导致系统资源的浪费和利用率降低。

2)系统性能下降

死锁会导致进程长时间等待,影响系统响应时间,严重时甚至可能让系统无法响应新的请求,导致性能显著下降。

3)系统稳定性降低

死锁使得部分进程停滞,从而影响依赖这些进程的其他部分,甚至导致整个系统失去响应,影响系统的稳定性和可靠性。

4. 如何避免死锁?

为了避免死锁的危害,通常需要在设计阶段进行预防,包括资源分配有序化、锁定顺序控制、减少锁的粒度等策略,同时在运行时进行死锁检测和恢复。

二、死锁示例

代码示例如下:

1 public class DeadLock {

2 /**

3 * 创建两个对象,用两个线程分别先后独占

4 */

5 private Boolean flag1 = true;

6 private Boolean flag2 = false;

7

8 public static void main(String[] args) {

9 DeadLock deadLock = new DeadLock();

10

11 new Thread(new Runnable() {

12 @Override

13 public void run() {

14 System.out.println("线程1开始,作用是当flag1 = true 时,将flag2也改为 true");

15 synchronized (deadLock.flag1){

16 if(deadLock.flag1){

17 try{

18 //睡眠1s ,模拟业务执行耗时,并保证两个线程进入死锁状态

19 Thread.sleep(1000);

20 }catch (InterruptedException e){

21 e.printStackTrace();

22 }

23 System.out.println("flag1 = true,准备锁住flag2...");

24 synchronized (deadLock.flag2){

25 deadLock.flag2 = true;

26 }

27 }

28 }

29 }

30 }).start();

31

32 new Thread(new Runnable() {

33 @Override

34 public void run() {

35 System.out.println("线程2开始,作用是当flag2 = false 时,将flag1也改为 false");

36 synchronized (deadLock.flag2){

37 if(!deadLock.flag2){

38 try{

39 //睡眠1s ,模拟业务执行耗时,并保证两个线程进入死锁状态

40 Thread.sleep(1000);

41 }catch (InterruptedException e){

42 e.printStackTrace();

43 }

44 System.out.println("flag2 = false,准备锁住flag1...");

45 synchronized (deadLock.flag1){

46 deadLock.flag1 = false;

47 }

48

49 }

50 }

51 }

52 }).start();

53 }

54 }

三、死锁检测

1. jps

jps -l

查看所有的jvm进程,包括进程ID,进程启动的路径等等。

如下图:

2. jstack

jstack [pid]

jstack命令用于生成虚拟机当前时刻的线程快照。通过这个命令,可以观察jvm中当前所有线程的运行情况和线程当前状态。

执行命令:jstack 10928,截取部分运行结果,如下图:

3. 可视化工具 jconsole

从Java 5开始 引入了 JConsole,JConsole 是一个内置 Java 性能分析器。

主要用于基础的 JVM 监控,适合于查看应用程序的基本运行状况。它提供了一些基础指标,比如 CPU、内存使用率、线程状态、类加载信息以及基本的 MBeans 信息。它简单轻便,适合对应用进行基本的监控。

1)在命令终端输入:jconsole

2)点击连接进去

进入所检测的进程后,选择“线程”选项卡,并点击“检测死锁”。即可出来检测结果。如下图:

4. 可视化工具 visual VM

Visual VM 功能比 JConsole 更全面,除了 JConsole 提供的基础监控功能外,VisualVM 还支持更复杂的调试和性能分析。它可以进行 CPU 和内存的详细分析、线程分析、内存泄露检测,还可以生成堆转储文件、线程转储、GC 日志等,并支持通过插件扩展功能,比如集成 BTrace 进行动态追踪。

可以点击右上角Dump按钮,将线程的信息导出,其实就是执行的jstack命令

🖌️ 相关文章

《英雄联盟》msi2025参赛战队成员名单一览
365平台是什么

《英雄联盟》msi2025参赛战队成员名单一览

📅 08-05 👁️ 2916
宽带网上缴费多久能用
365bet官网娱乐网址

宽带网上缴费多久能用

📅 09-04 👁️ 7727
现在如何更新百度快照?
365平台是什么

现在如何更新百度快照?

📅 07-03 👁️ 3071