JUC之死锁编码及定位分析

74 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第31天,点击查看活动详情

死锁

死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力干涉那它们都将无法推进下去,如果系统资源充足,进程的资源请求都能够得到满足,死锁出现的可能性就很低,否则就会因争夺有限的资源而陷入死锁。

image-20200928100808516

通俗来讲就是,假如有两个人。一个是「灰姑娘」一个是「白雪公主」,灰姑娘手上拿着口红,白雪公主拿着镜子。突然灰姑娘想要镜子为自己画口红,白雪公主想要对着镜子为自己画口红。这不就大眼对小眼了,卡住了。口红和镜子只有一个,正常来说这时候就只能有一方让出自己的东西(正常人思维)。可是程序都是死死拿着自己手上的东西不可退让,因此产生了悲剧~也就是死锁。。。。

image-20200512215830203

//死锁:多个线程互相抱着对方需要的资源同时又请求对方的资源,然后形成僵持
public class TestDeadLock {
    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;//使用化妆品的人

    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);
            }
            synchronized (mirror) {//一秒后想要镜子
                System.out.println(this.girlName + "获得镜子的锁");
                Thread.sleep(1000);
            }
        } else {
            synchronized (mirror) {//获得镜子的锁
                System.out.println(this.girlName + "获得镜子的锁");
                Thread.sleep(1000);
            }
            synchronized (lipstick) {//一秒后想要口红的锁
                System.out.println(this.girlName + "获得口红的锁");
            }
        }
    }
}

编码

image-20200928100937419

public class DeadLockDemo {

    public static void main(String[] args) {
        String lockA = "lockA";
        String lockB = "lockB";
        new Thread(new MyThread(lockA, lockB), "T1").start();
        new Thread(new MyThread(lockB, lockA), "T2").start();
    }
}

class MyThread implements Runnable {

    private String lockA;
    private String lockB;

    public MyThread(String lockA, String lockB) {
        this.lockA = lockA;
        this.lockB = lockB;
    }

    @Override
    public void run() {
        synchronized (lockA) {
            System.out.println(Thread.currentThread().getName() + "lock:" + lockA + "=>get" + lockB);

            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            synchronized (lockB) {
                System.out.println(Thread.currentThread().getName() + "lock:" + lockB + "=>get" + lockA);
            }
        }
    }
}

image-20200928145657688

定位分析

中终端使用jps命令查看进程号定位。

image-20200928150041523

得到进程号6705

再使用jstack 进程号命令查看具体信息。

image-20200928150229965

可以看到引发死锁的具体原因!