Java线程死锁

死锁是一种特定的程序状态,在实体之间,由于循环依赖导致彼此一直处于等待之中,没有 任何个体可以继续前进。死锁不仅仅是在线程之间会发生,存在资源独占的进程之间同样也 可能出现死锁。通常来说,我们大多是聚焦在多线程场景中的死锁,指两个或多个线程之 间,由于互相持有对方需要的锁,而永久处于阻塞的状态。

Java线程死锁是一个经典的多线程问题,因为不同的线程都在等待那些根本不可能被释放的锁,从而导致所有的工作都无法完成。如图所示

图片说明


如何去定位Java线程死锁呢?

定位死锁最常见的方式就是利用 jstack 等工具获取线程栈,然后定位互相之间的依赖关系,进而找到死锁。如果是比较明显的死锁,往往 jstack 等就能直接定位,类似 JConsole 甚至可以在图形界面进行有限的死锁检测。
既然了解了用什么工具去定位线程死锁,那我们模拟一个Java线程死锁的情况,实战定位线程死锁
死锁代码:

/**
 * @Author:luomo
 * @CreateTime: 2020/3/28
 * @Description:模拟DeadLock
 */
public class deadLock implements Runnable{
    public static  Object obj1=new Object();
    public static  Object obj2=new Object();
    private int flag;
    deadLock(int flag){
        this.flag=flag;
    }

    @Override
    public void run() {
        if(flag==0){
            synchronized (obj1){
                System.out.println(Thread.currentThread().getName()+"成功获取锁1");
                try {
                    Thread.currentThread().sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"尝试获取锁2");
                synchronized (obj2){
                    System.out.println(Thread.currentThread().getName()+"成功获取锁2");


                }
            }
        }else{
            synchronized (obj2){
                System.out.println(Thread.currentThread().getName()+"成功获取锁2");
                try {
                    Thread.currentThread().sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName()+"尝试获取锁1");
                synchronized (obj1){
                    System.out.println(Thread.currentThread().getName()+"成功获取锁2");


                }
            }
        }

    }

    public static void main(String[] args) {
   deadLock d1=new deadLock(0);
   deadLock d2=new deadLock(1);
   Thread thread1=new Thread(d1);
   Thread thread2=new Thread(d2);
   thread1.start();
   thread2.start();

    }

}

代码运行:

从运行结果我们看到Thread1和Thread0同时都在争用对方已经占有的锁,进而产生死锁。


如何定位死锁

如果程序发生了死锁,我们如何去定位死锁?我们可以通过JConsole工具来发现死锁。
打开cmd:输入 JConsole 回车
我们可以看到一个可视化的工具,找到死锁进程点击连接

图片说明

我们可以看到有检查死锁的选项

图片说明

图片说明

图片说明

通过上图我们可以发现产生死锁的线程,从而定位到发生死锁的代码。

当然我们还可以使用Jstack + pid的方式来定位问题

图片说明