温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

Java基础:一个100%会发生死锁的程序

发布时间:2020-07-20 20:54:11 来源:网络 阅读:357 作者:沙漏半杯 栏目:编程语言

 多线程是Java工程师进阶所必须掌握的一项技能,也是面试中绕不过的一个环节,而死锁又是多线程同步失败的经典案例,对于复杂的系统,死锁是很难通过代码层面来做静态检测和排查的,所以有的面试官会从反向出发,让你手写一个死锁程序。
    先来看一个网络上常见的死锁程序(可能存在问题):

public class DeadLockTest {    private static Object lock1 = new Object();    private static Object lock2 = new Object();    public static void main(String[] args) {        new Thread(() -> {
            synchronized (lock1) {
                System.out.println("thread1 acquired lock1");                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("thread1 try to acquire lock2");
                synchronized (lock2) {
                    System.out.println("thread1 acquired lock2");
                }
            }
        }, "t1").start();        new Thread(() -> {
            synchronized (lock2) {
                System.out.println("thread2 acquired lock2");                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("thread2 try to acquire lock1");
                synchronized (lock1) {
                    System.out.println("thread2 acquired lock1");
                }
            }
        }, "t2").start();        
        // 检测死锁
        checkDeadLock();
        System.out.println("main thread end");
    }    public static void checkDeadLock() {
        ThreadMXBean mxBean = ManagementFactory.getThreadMXBean();
        ScheduledExecutorService scheduled = Executors.newScheduledThreadPool(1);        // 初始等待5秒,每隔10秒检测一次
        scheduled.scheduleAtFixedRate(()->{            long[] threadIds = mxBean.findDeadlockedThreads();            if (threadIds != null) {
                System.out.println("检测到死锁线程:");
                ThreadInfo[] threadInfos = mxBean.getThreadInfo(threadIds);                for (ThreadInfo info : threadInfos) {
                    System.out.println(info.getThreadId() + ":" + info.getThreadName());
                }
            }
        }, 5L, 10L, TimeUnit.SECONDS);
    }
}

    上面这段程序在99.99%的情况下都会发生死锁,但是从理论的角度来讲,死锁并不是100%会发生的,比如:线程t1先启动并获取了锁lock1,在休眠的这1s的过程中,JVM并未发生线程调度(实际上基本不可能),t2未得到执行也未获取到锁lock2,这时候t1休眠结束继续执行并获取了锁lock2,那么这种情况下就不会发生死锁了。
    如何写一个100%会发生死锁的程序呢?直接上代码:

public class DeadLockTest {    private static Object lock1 = new Object();    private static Object lock2 = new Object();    // 这里的flag需要用volatile修饰,以保证线程间的可见性
    private static volatile boolean flag1 = false;    private static volatile boolean flag2 = false;    public static void main(String[] args) {        new Thread(() -> {
            synchronized (lock1) {
                flag1 = true;
                System.out.println("thread1 acquired lock1");                while (!flag2) {                    // 无限循环,等待thread2获取到lock2后再继续往下执行(相比使用Thread.sleep(1000)在理论上是100%会出现死锁)
                    Thread.yield();
                }
                System.out.println("thread1 try to acquire lock2");
                synchronized (lock2) {
                    System.out.println("thread1 acquired lock2");
                }
            }
        }, "t1").start();        new Thread(() -> {
            synchronized (lock2) {
                flag2 = true;
                System.out.println("thread2 acquired lock2");                while (!flag1) {
                    Thread.yield();
                }
                System.out.println("thread2 try to acquire lock1");
                synchronized (lock1) {
                    System.out.println("thread2 acquired lock1");
                }
            }
        }, "t2").start();        // 检测死锁
        checkDeadLock();
        System.out.println("main thread end");
    }    public static void checkDeadLock() {
        ThreadMXBean mxBean = ManagementFactory.getThreadMXBean();
        ScheduledExecutorService scheduled = Executors.newScheduledThreadPool(1);        // 初始等待5秒,每隔10秒检测一次
        scheduled.scheduleAtFixedRate(() -> {            long[] threadIds = mxBean.findDeadlockedThreads();            if (threadIds != null) {
                System.out.println("检测到死锁线程:");
                ThreadInfo[] threadInfos = mxBean.getThreadInfo(threadIds);                for (ThreadInfo info : threadInfos) {
                    System.out.println(info.getThreadId() + ":" + info.getThreadName());
                }
            }
        }, 5L, 10L, TimeUnit.SECONDS);
    }
}


向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI