多线程是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);
}
}

Java基础:一个100%会发生死锁的程序的更多相关文章

  1. JAVA基础——最简单的多重循环程序

    Java 循环语句之多重循环 循环体中包含循环语句的结构称为多重循环.三种循环语句可以自身嵌套,也可以相互嵌套,最常见的就是二重循环.在二重循环中,外层循环每执行一次,内层循环要执行一圈. 如下所示: ...

  2. 3、Java基础语法(下):程序流程控制

    程序流程控制 从键盘获取不同类型的变量: 使用Scanner类,具体实现步骤: 1.导包:import java.util.Scanner; 2.Scanner的实例化:Scanner scan = ...

  3. Java基础之创建窗口——创建应用程序窗口(TryWindow)

    控制台程序. 准备好应用程序窗口及其包含的组件并显示,这称为实现窗口.调用应用程序窗口对象的setVisible()方法就会实现窗口.实现了应用程序的GUI之后,在主线程中修改或查询GUI可能会导致死 ...

  4. 利用java开发一个双击执行的小程序

    之前我们利用java写了很多东西,但是好像都没有什么实际意义. 因为有意义桌面小程序怎么都得有个界面,可是界面又不太好搞.或者 了解到这一层的人就少之又少了. 呀,是不是还得开辟一些版面来介绍awt和 ...

  5. Java基础:HashMap假死锁问题的测试、分析和总结

    前言 前两天在公司的内部博客看到一个同事分享的线上服务挂掉CPU100%的文章,让我联想到HashMap在不恰当使用情况下的死循环问题,这里做个整理和总结,也顺便复习下HashMap. 直接上测试代码 ...

  6. java基础/一个类A继承了类B,那么A就叫做B的派生类或子类,B就叫基类或超类。

    类重复,pulic class demo1 和class demo1 重复 无主类, 在cmd中输入命令: SET CLASSPATH=. (等号后为英文点符号),即可设置解释的路径为当前路径. 再次 ...

  7. Java.基础 -------- 一个Java源文件中可以有很多类,但只能有一个类是public的

    一个Java源文件中可以有很多类,但只能有一个类是public的        Java程序是从一个public类main函数开始执行的,只能有一个public是为了给类装载器提供方便,一个publi ...

  8. java实现一个简单的爬虫小程序

    前言 前些天无意间在百度搜索了一下以前写过的博客 我啥时候在这么多不知名的网站上发表博客了???点进去一看, 内容一模一样,作者却不是我... 然后又去搜了其他篇博客,果然,基本上每篇都在别的网站上有 ...

  9. Java基础-一个java文件多个类的问题

    一个.java文件当然可以包括多个类.但这些类有一个特殊的类与其它的不同,,这个类是带public 属性的类.一个.java类文件中仅有一个public属性的类.而且这个类与文件名相同.

随机推荐

  1. Linux 搭建 Nginx+PHP-FPM环境

    安装PHP.Nginx和PHP-FPM sudo apt-get install php sudo apt-get install nginx sudo apt-get install php7-fp ...

  2. java爬虫案例学习

    最近几天很无聊,学习了一下java的爬虫,写一些自己在做这个案例的过程中遇到的问题和一些体会1.学习目标         练习爬取京东的数据,图片+价格+标题等等 2.学习过程 1·开发工具      ...

  3. tomcat +jenkios

    来源:https://www.cnblogs.com/edward2013/p/5269465.html 1. 安装JDK JDK下载地址:  http://www.oracle.com/techne ...

  4. 如何在Linux下查看版本信息

    Linux下如何查看版本信息, 包括位数.版本信息以及CPU内核信息.CPU具体型号等等,整个CPU信息一目了然.   1.# uname -a   (Linux查看版本当前操作系统内核信息)   L ...

  5. [Swift]LeetCode740. 删除与获得点数 | Delete and Earn

    Given an array nums of integers, you can perform operations on the array. In each operation, you pic ...

  6. 利用U盘安装win2008r2系统的步骤

    我们在公司或者家里,经常要安装各种系统,最近公司需要重新安装win2008r2系统.折腾了一天的时间,终于把系统装好了.将安装的步骤记录下来,方便大家查看,自己也做个记录. 1 准备win2008r2 ...

  7. Java8 LocalDateTime获取时间戳(毫秒/秒)、LocalDateTime与String互转、Date与LocalDateTime互转

    本文目前提供:LocalDateTime获取时间戳(毫秒/秒).LocalDateTime与String互转.Date与LocalDateTime互转 文中都使用的时区都是东8区,也就是北京时间.这是 ...

  8. 4.Django模板语言和分页

    继承 extends 子版只能继承一个父模板 1.父模板 master.html <!DOCTYPE html> <html lang="en"> < ...

  9. 【WebAPI No.4】Swagger实现API文档功能

    介绍: Swagger也称为Open API,Swagger从API文档中手动完成工作,并提供一系列用于生成,可视化和维护API文档的解决方案.简单的说就是一款让你更好的书写API文档的框架. 我们为 ...

  10. c 编译器大全

    c 编译器大全 看了下nginx的auto/cc下的目录,nginx对多种c语言的编辑器都进行了支持.才知道c语言有那么多编辑器. 编译器原理 所谓编译器,就是执行下面的三步骤: 1 将目标语言转换为 ...