多线程是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. Javaweb-request与response

                           Javaweb-request与response              Servlet   生命周期(什么时候创建的,什么时候销毁的);     Se ...

  2. php 跨数据库调取数据

    我的这个是thinkphp,我就在 Application -> Common -> Conf -> config.php 文件里面配置数据库的地方,加入了下面这段代码 //'数据库 ...

  3. maven_SSM集成的demo

    一.集成spring 二.集成springMVC 三.集成mybatis 1. pom.xml <?xml version="1.0" encoding="UTF- ...

  4. JS基础整理

    使用JS的三种方式 1.直接在html标签中,使用事件属性,调用js代码 <button onclick="alert('弹框')">弹框!</button> ...

  5. [Swift]LeetCode136. 只出现一次的数字 | Single Number

    Given a non-empty array of integers, every element appears twice except for one. Find that single on ...

  6. [Swift]LeetCode353. 设计贪吃蛇游戏 $ Design Snake Game

    Design a Snake game that is played on a device with screen size = width x height. Play the game onli ...

  7. Java 生成 JNI 头文件

    [参考文章]:javah javac 命令行生成native的方法教程 [参考文章]:用javah 导出类的头文件, 常见的错误及正确的使用方法 项目需要调用 C++动态库,由于项目包结构发生变化,需 ...

  8. iOS学习——核心动画之Layer基础

    iOS学习——核心动画之Layer基础 1.CALayer是什么? CALayer我们又称它叫做层.在每个UIView内部都有一个layer这样一个属性,UIView之所以能够显示,就是因为它里面有这 ...

  9. python网络-TFTP客户端开发(25)

    一. TFTP协议介绍 TFTP(Trivial File Transfer Protocol,简单文件传输协议) 是TCP/IP协议族中的一个用来在客户端与服务器之间进行简单文件传输的协议 特点: ...

  10. Cassandra与Mongo的事务实现之分布式协议

    摘要 NoSql不同于关系型数据库,是分布式存储,因此想要实现关系型数据库中的事务就不是那么简单了.本文结合Cassandra中的paxos和Mongo的two phase commit来谈谈Nosq ...