前言
Java的多线程死锁是一种常见的并发问题。它发生在两个或多个线程相互等待对方释放资源,导致程序陷入僵局。死锁可能会导致应用程序停止响应,严重影响性能和可靠性。通常,死锁的发生是由于线程争夺资源的顺序不当或未能释放资源引起的。要解决死锁问题,开发者需要仔细设计线程同步策略,使用锁的层次结构,并确保及时释放锁资源,以避免潜在的死锁风险。
死锁
多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。
如下图所示,线程 A 持有资源 2,线程 B 持有资源 1,他们同时都想申请对方的资源,所以这两个线程就会互相等待而进入死锁状态。
示例:
public class DeadLockDemo { private static Object lock1 = new Object();//锁1,资源1 private static Object lock2 = new Object();//锁2,资源2 public static void main(String[] args) { //启动一个线程 new Thread(new Runnable() { @Override public void run() { synchronized(lock1){ System.out.println(Thread.currentThread().getName()+"拿到了锁1,资源1"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"等待锁2,资源2"); synchronized (lock2){ System.out.println(Thread.currentThread().getName()+"拿到了锁2,资源2"); } } } },"线程1").start(); //产生死锁的线程 // new Thread(new Runnable() { // @Override // public void run() { // synchronized(lock2){ // System.out.println(Thread.currentThread().getName()+"拿到了锁2,资源2"); // try { // Thread.sleep(1000); // } catch (InterruptedException e) { // e.printStackTrace(); // } // System.out.println(Thread.currentThread().getName()+"等待锁1,资源1"); // synchronized (lock1){ // System.out.println(Thread.currentThread().getName()+"拿到了锁1,资源1"); // } // } // } // },"线程2").start(); } }
线程 A 通过 synchronized (resource1) 获得 resource1 的监视器锁,然后通过Thread.sleep(1000);
让线程 A 休眠 1s 为的是让线程 B 得到执行然后获取到 resource2 的监视器锁。线程 A 和线程 B 休眠结束了都开始企图请求获取对方的资源,然后这两个线程就会陷入互相等待的状态,这也就产生了死锁。
破坏死锁
//破坏死锁 new Thread(new Runnable() { @Override public void run() { synchronized(lock1){ System.out.println(Thread.currentThread().getName()+"拿到了锁1,资源1"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+"等待锁2,资源2"); synchronized (lock2){ System.out.println(Thread.currentThread().getName()+"拿到了锁2,资源2"); } } } },"线程2").start();
线程 1 首先获得到 resource1 的监视器锁,这时候线程 2 就获取不到了。然后线程 1 再去获取 resource2 的监视器锁,可以获取到。然后线程 1 释放了对 resource1、resource2 的监视器锁的占用,线程 2 获取到就可以执行了。这样就破坏了破坏循环等待条件,因此避免了死锁。
最后
本期结束咱们下次再见👋~
🌊 关注我不迷路,如果本篇文章对你有所帮助,或者你有什么疑问,欢迎在评论区留言,我一般看到都会回复的。大家点赞支持一下哟~ 💗