Java基础:一个100%会发生死锁的程序
程序员文章站
2022-03-30 21:19:11
多线程是Java工程师进阶所必须掌握的一项技能,也是面试中绕不过的一个环节,而死锁又是多线程同步失败的经典案例,对于复杂的系统,死锁是很难通过代码层面来做静态检测和排查的,所以有的面试官会从反向出发,让你手写一个死锁程序。 &n ......
多线程是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(); 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); } }
推荐阅读
-
java基础------环境变量的配置及编写第一个程序
-
Java经典编程习题100例:第18例:编写程序,将一个数组中的元素倒排过来。例如原数组为1,2,3,4,5;则倒排后数组中的值
-
JAVA 基础 / 第四课:在ECLIPSE中运行第一个 JAVA 程序以及找不到类的问题
-
Java基础:一个100%会发生死锁的程序
-
java基础------环境变量的配置及编写第一个程序
-
编写一个Java应用程序,产生20个50-100之内的整数,并输出这20个数并找出最大数及最小数输出
-
Java基础:一个100%会发生死锁的程序
-
JAVA 基础 / 第四课:在ECLIPSE中运行第一个 JAVA 程序以及找不到类的问题
-
编写一个Java应用程序,产生10个100之内的随机整数输出,并把这10个数从小到大的顺序输出