java死锁怎么排查

什么是线程死锁

死锁是指两个或两个以上的线程在执行过程中,因争夺资源而造成的互相等待的现象,

在无外力作用的情况下,这些线程会 直相互等待而无法继续运行下去。如图所示

image-20210409205202988

在图中,线程A已经持有了资源2, 同时还想申请资源1,线程B已经持有了资源 1,它同时还想申请资源2 ,

所以线程A和线程B就因为相互等待对方已经持有的资源,而进入了死锁状态。

死锁的必要条件

  1. 互斥条件:进程要求对所分配的资源(如打印机)进行排他性控制,即在一段时间内某资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待
  2. 不可剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能由获得该资源的进程自己来释放(只能是主动释放)。
  3. 请求并保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放
  4. 循环等待条件:存在一种进程资源的循环等待链,链中每一个进程已获得的资源同时被 链中下一个进程所请求。即存在一个处于等待状态的进程集合{Pl, P2, …, pn},其中Pi等 待的资源被P(i+1)占有(i=0, 1, …, n-1),Pn等待的资源被P0占有

程序出现死锁怎么排查

让我们看一段代码,这段代码会出现死锁

public class DeadLockDemo {
    private static String A = "A";
    private static String B = "B";

    public static void main(String[] args) {
        new DeadLockDemo().deadLock();
    }

    private void deadLock() {
        Thread t1 = new Thread(()->{
            synchronized (A) {
                try {
                    Thread.sleep(2000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                synchronized (B) {
                    System.out.println("1");
                }
            }
        });
        Thread t2 = new Thread(()->{
            synchronized (B) {
                synchronized (A) {
                    System.out.println("1");
                }
            }
        });
        t1.start();
        t2.start();
    }
}

一旦出现死锁,业务是可感知的,因为不能继续提供服务了,那么只能通过dump线程看看是哪个线程出现了问题

  1. jps查看java进程,找到死锁进程的进程号

    image-20210409205917353
  2. 使用jstack 5632 > ~/Downloads/dump5632导出dump文件

  3. 查看dump文件内容,这里我们看到如下内容

    "Thread-1" #12 prio=5 os_prio=31 tid=0x00007fe95a86a000 nid=0x5703 waiting for monitor entry [0x00007000043ea000]
       java.lang.Thread.State: BLOCKED (on object monitor)
    	at java并发编程的艺术.ch01.DeadLockDemo.lambda$deadLock$1(DeadLockDemo.java:34)
    	- waiting to lock <0x000000076ac28aa0> (a java.lang.String)
    	- locked <0x000000076ac28ad0> (a java.lang.String)
    	at java并发编程的艺术.ch01.DeadLockDemo$$Lambda$2/1329552164.run(Unknown Source)
    	at java.lang.Thread.run(Thread.java:748)
    
    "Thread-0" #11 prio=5 os_prio=31 tid=0x00007fe95a869000 nid=0xa803 waiting for monitor entry [0x00007000042e7000]
       java.lang.Thread.State: BLOCKED (on object monitor)
    	at java并发编程的艺术.ch01.DeadLockDemo.lambda$deadLock$0(DeadLockDemo.java:27)
    	- waiting to lock <0x000000076ac28ad0> (a java.lang.String)
    	- locked <0x000000076ac28aa0> (a java.lang.String)
    	at java并发编程的艺术.ch01.DeadLockDemo$$Lambda$1/381259350.run(Unknown Source)
    	at java.lang.Thread.run(Thread.java:748)
    

    我们知道是DeadLockDemo的第32行和27行引起的死锁

避免死锁的常见方法

最后介绍下避免死锁的常见方法

  1. 避免一个线程同时获取多个锁
  2. 避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源
  3. 尝试使用定时锁,使用lock.tryLock(time)来替代使用内部锁机制
  4. 对于数据库锁,加锁和解锁必须在一个库连接里,否则会出现解锁失败的情况
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值