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的方式来定位问题