Java基础:一个100%会发生死锁的程序
多线程是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%会发生死锁的程序的更多相关文章
- JAVA基础——最简单的多重循环程序
Java 循环语句之多重循环 循环体中包含循环语句的结构称为多重循环.三种循环语句可以自身嵌套,也可以相互嵌套,最常见的就是二重循环.在二重循环中,外层循环每执行一次,内层循环要执行一圈. 如下所示: ...
- 3、Java基础语法(下):程序流程控制
程序流程控制 从键盘获取不同类型的变量: 使用Scanner类,具体实现步骤: 1.导包:import java.util.Scanner; 2.Scanner的实例化:Scanner scan = ...
- Java基础之创建窗口——创建应用程序窗口(TryWindow)
控制台程序. 准备好应用程序窗口及其包含的组件并显示,这称为实现窗口.调用应用程序窗口对象的setVisible()方法就会实现窗口.实现了应用程序的GUI之后,在主线程中修改或查询GUI可能会导致死 ...
- 利用java开发一个双击执行的小程序
之前我们利用java写了很多东西,但是好像都没有什么实际意义. 因为有意义桌面小程序怎么都得有个界面,可是界面又不太好搞.或者 了解到这一层的人就少之又少了. 呀,是不是还得开辟一些版面来介绍awt和 ...
- Java基础:HashMap假死锁问题的测试、分析和总结
前言 前两天在公司的内部博客看到一个同事分享的线上服务挂掉CPU100%的文章,让我联想到HashMap在不恰当使用情况下的死循环问题,这里做个整理和总结,也顺便复习下HashMap. 直接上测试代码 ...
- java基础/一个类A继承了类B,那么A就叫做B的派生类或子类,B就叫基类或超类。
类重复,pulic class demo1 和class demo1 重复 无主类, 在cmd中输入命令: SET CLASSPATH=. (等号后为英文点符号),即可设置解释的路径为当前路径. 再次 ...
- Java.基础 -------- 一个Java源文件中可以有很多类,但只能有一个类是public的
一个Java源文件中可以有很多类,但只能有一个类是public的 Java程序是从一个public类main函数开始执行的,只能有一个public是为了给类装载器提供方便,一个publi ...
- java实现一个简单的爬虫小程序
前言 前些天无意间在百度搜索了一下以前写过的博客 我啥时候在这么多不知名的网站上发表博客了???点进去一看, 内容一模一样,作者却不是我... 然后又去搜了其他篇博客,果然,基本上每篇都在别的网站上有 ...
- Java基础-一个java文件多个类的问题
一个.java文件当然可以包括多个类.但这些类有一个特殊的类与其它的不同,,这个类是带public 属性的类.一个.java类文件中仅有一个public属性的类.而且这个类与文件名相同.
随机推荐
- ElasticSearch(6.2.2)的java API官方文档的总结 (三)
一 : SearchRequest用于任何与搜索文档,聚合和建议有关的操作,并且还提供了对生成的文档进行高亮显示的方法. 在最基本的形式中,我们可以向请求添加一个查询: 1:添加一个Search ...
- python 用正则处理日志实例
前提: 了解正则基本语法 import re with open('top10_xiaozhuang_net.log','r') as f1: #读取日志文件 subject=f1.rea ...
- CSS引用方式及样式层叠机制
CSS引用方式有3种,三种分别为:外部引入.内部引入.行内样式,下面一 一进行介绍. 1.外部引入:CSS代码在一个独立的文件中,HTML通过Link标签引入到页面. 代码格式:<link re ...
- Ajax刷新DIV内容
Ajax刷新DIV内容 实现了网页的异步数据处理,不用刷新整个页面 <标签 onmouseover="method"/ >method:这个参数是处理onmouseov ...
- 多选ui实现单选效果
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- Go语言数组和切片的原理
目录 数组 创建 访问和赋值 切片 结构 初始化 访问 追加 拷贝 总结 数组和切片是 Go 语言中常见的数据结构,很多刚刚使用 Go 的开发者往往会混淆这两个概念,数组作为最常见的集合在编程语言中是 ...
- Pycharm中配置鼠标悬停快速提示方法参数
第一步: 第二步: 演示:
- CentOS7Linux中自动化运维工具Ansible的安装,以及通过模块批量管理多台主机
使用自动化运维工具Ansible集中化管理服务器 Ansible概述 Ansible是一款为类Unix系统开发的自由开源的配置和自动化工具.它用Python写成,类似于saltstack和Puppet ...
- 【Scala篇】--Scala中集合数组,list,set,map,元祖
一.前述 Scala在常用的集合的类别有数组,List,Set,Map,元祖. 二.具体实现 数组 1.创建数组 new Array[Int](10) 赋值:arr(0) = xxx Array[ ...
- spark能传递外部命名参数给main函数吗?
查了资料好像都没有办法.只能通过: def main(args: Array[String]): Unit = { // 读取参数 var city = args(0) var input = arg ...