java死锁怎么用jvm调试_一篇文章搞清JVM死锁问题及排查

关于死锁,一直是面试和日常开发中的熟悉话题,本文将进行一下探讨:

什么是死锁

出现死锁的原因

如何避免死锁

代码中死锁问题怎么排查

@

1. 什么是死锁

死锁是指两个或两个以上的进程或线程,在执行过程中,由于竞争资源而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去

划重点:两个或两个以上进程或线程,竞争资源,最终阻塞无法进行下去

这里可能会问:外力作用是什么外力?资源剥夺;撤销进程;进程回退等

2. 出现死锁的原因

系统资源不足;

进程推进顺序非法

系统资源分配不当。

另外,信号量使用不当也会造成死锁。比如A等B消息,B等A的消息

死锁产生的有4个必要条件

(1) 互斥条件:一个资源每次只能被一个进程使用。

(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。

(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。

(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

3. 如何预防和避免死锁

预防:

死锁的预防基本思想打破产生死锁的四个必要条件中的一个或几个,保证系统不会进入死锁状态。

比如:

打破互斥条件:允许进程同时访问某些资源

打破不剥夺条件:允许进程从占有者占有的资源中强行剥夺一些资源

打破请求与保持条件:进程在运行前一次性地向系统申请它所需要的全部资源

打破循环等待条件:实行资源有序分配策略

避免:

加锁顺序(线程按照一定的顺序加锁)

加锁时限(线程尝试获取锁的时候加上一定的时限,超过时限则放弃对该锁的请求,并释放自己占有的锁)

死锁检测

阿里巴巴中最新的开发规约,里面有对避免死锁的说明,具体如下:

【强制】对多个资源、数据库表、对象同时加锁时,需要保持一致的加锁顺序,否则可能会造成死锁。 说明:线程一需要对表 A、B、C 依次全部加锁后才可以进行更新操作,那么线程二的加锁顺序也必须是 A、B、C,否则可能出现死锁。

4. 实战JVM死锁问题排查

4.1 死锁代码案例

按照死锁产生原则,可写出一个产生死锁的程序

public class DeadLock {

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

private Boolean flag1 = true;

private Boolean flag2 = false;

public static void main(String[] args) {

DeadLock deadLock = new DeadLock();

new Thread(new Runnable() {

@Override

public void run() {

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

synchronized (deadLock.flag1){

if(deadLock.flag1){

try{

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

Thread.sleep(1000);

}catch (InterruptedException e){

e.printStackTrace();

}

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

synchronized (deadLock.flag2){

deadLock.flag2 = true;

}

}

}

}

}).start();

new Thread(new Runnable() {

@Override

public void run() {

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

synchronized (deadLock.flag2){

if(!deadLock.flag2){

try{

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

Thread.sleep(1000);

}catch (InterruptedException e){

e.printStackTrace();

}

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

synchronized (deadLock.flag1){

deadLock.flag1 = false;

}

}

}

}

}).start();

}

}

以上代码,可以用一个死锁的图解释。线程1独占对象1,想要访问对象2,而对象2此时已经独占对象2,在等待对象1的资源释放,此时线程1因无法获取到对象2而无法向下执行,因此没法释放对象1,线程2同理,造成了死锁状态,两个线程都阻塞在等待资源处

4.2 死锁问题JVM工具排查

4.2.1 jps+jstack方式排查

查找程序运行端口

> jps -l

18714 sun.tools.jps.Jps

18703 jvm.DeadLock

jstack打印堆栈信息,发现死锁存在的位置,进行排查

> jstack -l 18703

dd445bac9537a3cd30979d1d21a33ca1.png

4.2.2 jconsole方式排查

mac下:输入jconsol命令通过可视化界面连接

8decb51e083ec28d4e27ce7309171505.png

选择线程,监测死锁。会将死锁的线程信息都展示出来

4140e3840e1e485444be12bf606e61ce.png

19d8af4b3fd1e8a38024ba0b6647d8e5.png

4.2.3 jvisualvm方式

用命令行召唤出jconsole,选择对应进程即可直观看到死锁的存在

c8457a09e7946bd1041f712695f5bdee.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值