解锁Java多线程编程中的死锁之谜

2023-09-27 21:55:28 浏览数 (1)

前言

Java的多线程死锁是一种常见的并发问题。它发生在两个或多个线程相互等待对方释放资源,导致程序陷入僵局。死锁可能会导致应用程序停止响应,严重影响性能和可靠性。通常,死锁的发生是由于线程争夺资源的顺序不当或未能释放资源引起的。要解决死锁问题,开发者需要仔细设计线程同步策略,使用锁的层次结构,并确保及时释放锁资源,以避免潜在的死锁风险。

死锁

多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。

如下图所示,线程 A 持有资源 2,线程 B 持有资源 1,他们同时都想申请对方的资源,所以这两个线程就会互相等待而进入死锁状态。

imgimg

示例:

代码语言:java复制
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 休眠结束了都开始企图请求获取对方的资源,然后这两个线程就会陷入互相等待的状态,这也就产生了死锁。

imgimg

破坏死锁

代码语言:java复制
 //破坏死锁
        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 获取到就可以执行了。这样就破坏了破坏循环等待条件,因此避免了死锁。

输入图片说明输入图片说明

最后

本期结束咱们下次再见

0 人点赞