死锁

HeJin大约 2 分钟Java多线程详解

多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能运行。从而导致两个或者多个线程都在等待对方释放资源,都停止执行的情形。某一个同步块同时拥有两个以上对象的锁时,就可能会发生死锁的问题。

多个线程互相抱着对方需要的资源,然后形成僵持。

**
 * @Desc 死锁:多个线程互相抱着对方需要的资源,然后形成僵持。
 * @Author HeJin
 * @Date 2021/3/10 19:07
 */
public class DeadLock {
    public static void main(String[] args) {
        Makeup g1 = new Makeup(0, "灰姑凉");
        Makeup g2 = new Makeup(1, "白雪公主");

        g1.start();
        g2.start();
    }
}

/**
 * 口红
 */
class Lipstick{
}

/**
 * 镜子
 */
class Mirror{
}

class Makeup extends Thread{
    /**
     * 需要的资源只有一份。用static来保证只有一份
     */
    static Lipstick lipstick = new Lipstick();
    static Mirror mirror = new Mirror();

    /** 选择 **/
    int choice;
    /** 名字 **/
    String girlName;

    public Makeup(int choice, String girlName){
        this.choice = choice;
        this.girlName = girlName;
    }

    @Override
    public void run() {
        // 化妆
        try {
            makeUp();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 化妆:互相持有对方的锁,就是要拿到对方的资源
     */
    private void makeUp() throws InterruptedException {
        if (choice == 0){
            // 获得口红的锁
            synchronized (lipstick){
                System.out.println(this.girlName + "获得口红的锁");
                Thread.sleep(1000);
                // 1秒钟后想获得镜子
                synchronized (mirror){
                    System.out.println(this.girlName + "获得镜子的锁");
                }
            }
        } else {
            synchronized (mirror){
                System.out.println(this.girlName + "获得镜子的锁");
                Thread.sleep(2000);
                // 1秒钟后想获得镜子
                synchronized (lipstick){
                    System.out.println(this.girlName + "获得口红的锁");
                }
            }
        }
    }
}

测试会发现程序卡死:

灰姑凉获得口红的锁
白雪公主获得镜子的锁

修改makeUp()方法:

private void makeUp() throws InterruptedException {
    if (choice == 0){
        // 获得口红的锁
        synchronized (lipstick){
            System.out.println(this.girlName + "获得口红的锁");
            Thread.sleep(1000);
        }
        // 1秒钟后想获得镜子
        synchronized (mirror){
            System.out.println(this.girlName + "获得镜子的锁");
        }
    } else {
        synchronized (mirror){
            System.out.println(this.girlName + "获得镜子的锁");
            Thread.sleep(2000);
        }
        // 1秒钟后想获得镜子
        synchronized (lipstick){
            System.out.println(this.girlName + "获得口红的锁");
        }
    }
}
灰姑凉获得口红的锁
白雪公主获得镜子的锁
白雪公主获得口红的锁
灰姑凉获得镜子的锁

Process finished with exit code 0

产生死锁的四个必要条件

  • 互斥条件:一个资源每次只能被一个进程使用。
  • 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
  • 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
  • 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。

上面列出了死锁的四个必要条件,我们只要想办法破坏其中的任意一个或多个条件就可以避免死锁发生。