0
点赞
收藏
分享

微信扫一扫

#yyds干货盘点#什么是死锁以及如何解决死锁

死锁是指两个或多个线程在互相等待对方释放锁的状态,从而导致程序无法继续执行的情况。

在Java多线程中,死锁通常是由于以下四种情况的组合所导致的:

  1. 互斥:多个线程竞争同一资源(如锁),每次只能有一个线程占用,其他线程必须等待。
  2. 占有且等待:线程在持有锁的同时,等待其他线程持有的锁。
  3. 不可抢占:已经获取锁的线程不能被其他线程强制中断或释放锁。
  4. 循环等待:多个线程形成一个循环等待的关系,每个线程都在等待其他线程释放锁。

要解决死锁问题,可以采取以下措施:

  1. 避免使用多个锁:尽量使用单个锁或者使用更高级别的同步机制,比如并发集合。
  2. 统一获取锁的顺序:确保所有线程获取锁的顺序一致,避免出现循环等待的情况。
  3. 尽可能缩小同步代码块:减少同步代码块的长度,缩小互斥的范围。
  4. 及时释放锁:尽可能早地释放锁,避免占有且等待的情况。
  5. 使用定时锁:在获取锁时,使用带有超时时间的锁,避免因为等待锁而导致死锁。
  6. 强制中断线程:在发现死锁时,可以强制中断其中一个线程,打破循环等待的环。

需要注意的是,死锁是一个复杂的问题,解决起来也比较困难,需要仔细分析代码和调试。

public class DeadLock {
    public static void main(String[] args) {
        Object lockA = new Object();
        Object lockB = new Object();
 
        Thread t1 = new Thread(() -> {
            // 1.占有一把锁
            synchronized (lockA) {
                System.out.println("线程1获得锁A");
                // 休眠1s(让线程2有时间先占有锁B)
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 获取线程2的锁B
                synchronized (lockB) {
                    System.out.println("线程1获得锁B");
                }
            }
        });
        t1.start();
 
        Thread t2 = new Thread(() -> {
            // 占B锁
            synchronized (lockB) {
                System.out.println("线程2获得锁B");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // 获取线程1的锁A
                synchronized (lockA) {
                    System.out.println("线程2获得了锁A");
                }
            }
        });
        t2.start();
    }
}

运行结果:

#yyds干货盘点#什么是死锁以及如何解决死锁_System

这段代码是一个典型的死锁示例,它包含两个线程,每个线程都持有一个锁并等待另一个锁的释放,从而导致死锁。

具体来说,这里定义了两个对象锁 lockA 和 lockB,并在两个线程中分别获取这两个锁。当线程1获取锁A后,它会休眠1秒钟,然后尝试获取锁B;而当线程2获取锁A后,它也会休眠1秒钟,然后尝试获取锁B。由于两个线程都在等待对方释放锁,因此它们会一直阻塞在获取锁的代码块中,无法继续执行,从而形成了死锁。

要解决这个问题,可以按照避免死锁的几种方法之一,例如对锁的获取顺序进行统一、尽量缩小同步代码块的范围、及时释放锁等。下面是一种修改方案:

public class UnDeadLock2 {
    public static void main(String[] args) {
        Object lockA = new Object();
        Object lockB = new Object();
 
        Thread t1 = new Thread(() -> {
            synchronized (lockA) {
                System.out.println("线程1得到锁A");
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lockB) {
                    System.out.println("线程1得到锁B");
                    System.out.println("线程1释放锁B");
                }
                System.out.println("线程1释放锁A");
            }
        }, "线程1");
        t1.start();
 
        Thread t2 = new Thread(() -> {
            synchronized (lockA) {
                System.out.println("线程2得到锁A");
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (lockB) {
                    System.out.println("线程2得到锁B");
                    System.out.println("线程2释放锁B");
                }
                System.out.println("线程2释放锁A");
            }
        }, "线程2");
        t2.start();
    }
}

在修改后的代码中,两个线程都按照相同的顺序获取锁(先获取锁A,再获取锁B),从而避免了死锁问题。此外,线程2也及时释放了锁A,避免了占有且等待的情况。

运行结果:

#yyds干货盘点#什么是死锁以及如何解决死锁_同步代码块_02

举报

相关推荐

0 条评论