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命令

posted @   欢乐豆123  阅读(474)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)
历史上的今天:
2020-11-10 Mysql的联(复)合索引
点击右上角即可分享
微信分享提示