文章目录

  • ManagementFactory介绍
  • 死锁检测与恢复介绍
  • 代码
    • 公共资源类
    • 导致死锁的模型
    • 模型实现类
    • 模拟死锁的程序类

ManagementFactory介绍

关于ManagementFactory:
ManagementFactory是一个可以获取JVM线程、内存、编译等信息的一个工厂类

    OperatingSystemMXBean system = ManagementFactory.getOperatingSystemMXBean();//相当于System.getProperty("os.name").System.out.println("系统名称:"+system.getName());//相当于System.getProperty("os.version").System.out.println("系统版本:"+system.getVersion());system.getSystemLoadAverage();// 返回最后一分钟的系统平均负载。 系统平均负载是排队到可用处理器的可运行实体的数量与在一段时间内平均运行在可用处理器上的可运行实体的数量之和。 计算负载平均值的方式是特定于操作系统的,但通常是阻尼时间相关的平均值。如果平均负载不可用,则返回负值。此方法旨在提供有关系统负载的提示,可能会被频繁查询。 在某些平台上,负载平均值可能不可用,因为实现此方法的成本很高。

死锁检测与恢复介绍

由于导致死锁的线程的不可控性(比如第三方软件启动的线程),因此死锁恢复的实际可操作性并不强:对死锁进行的故障恢复尝试可能是徒劳的(故障线程可无法响应中断)且有害的(可能导致活锁等问题)。 死锁的自动恢复有赖于线程的中断机制,其基本思想是:定义一个工作者线程DeadlockDetector专门用于死锁检测与恢复。该线程定期检测系统中是否存在死锁,若检测到死锁,则随机选取一个死锁线程并给其发送中断。该中断使得一个任意的死锁线程(目标线程)被Java虚拟机唤醒,从而使其抛出InterruptedException异常。这使得目标线程不再等待它本来永远也无法申请到的资源,从而破坏了死锁产生的必要条件中的“占用并等待资源”中的“等待资源”部分。
目标线程则通过对InterruptedException进行处理的方式来响应中断:目标线程捕获InterruptedException异常后将其已经持有的资源(锁)主动释放掉,这相当于破坏了死锁产生的必要条件中的“占用并等待资源”中的“占用资源”部分。接着,DeadlockDetector继续检测系统中是否仍然存在死锁,若存在,则继续选中一个任意的死锁线程并给其发送中断,直到系统中不再存在死锁。

用 ManagementFactory检测死锁:
需要用到getThreadMXBean()方法,这个方法返回 Java 虚拟机的线程系统的托管 bean。

代码

检测死锁的线程:

//工作者线程
public class DeadlockDetector extends Thread {static final ThreadMXBean tmb = ManagementFactory.getThreadMXBean();/*** 检测周期(单位为毫秒)*/private final long monitorInterval;
//ManagementFactory是一个可以获取JVM线程、内存、编译等信息的一个工厂类public DeadlockDetector(long monitorInterval) {super("DeadLockDetector");setDaemon(true);this.monitorInterval = monitorInterval;}public DeadlockDetector() {this(2000);}public static ThreadInfo[] findDeadlockedThreads() {long[] ids = tmb.findDeadlockedThreads();return null == tmb.findDeadlockedThreads() ?new ThreadInfo[0] : tmb.getThreadInfo(ids);}public static Thread findThreadById(long threadId) {for (Thread thread : Thread.getAllStackTraces().keySet()) {if (thread.getId() == threadId) {return thread;}}return null;}public static boolean interruptThread(long threadID) {Thread thread = findThreadById(threadID);if (null != thread) {thread.interrupt();return true;}return false;}@Overridepublic void run() {ThreadInfo[] threadInfoList;ThreadInfo ti;int i = 0;try {for (;;) {// 检测系统中是否存在死锁threadInfoList = DeadlockDetector.findDeadlockedThreads();if (threadInfoList.length > 0) {// 选取一个任意的死锁线程ti = threadInfoList[i++ % threadInfoList.length];Debug.error("Deadlock detected,trying to recover"+ " by interrupting%n thread(%d,%s)%n",ti.getThreadId(),ti.getThreadName());// 给选中的死锁线程发送中断DeadlockDetector.interruptThread(ti.getThreadId());continue;} else {Debug.info("No deadlock found!");i = 0;}Thread.sleep(monitorInterval);}// for循环结束} catch (InterruptedException e) {// 什么也不做;}}
}

DeadlockDetector是通过java.lang.management.ThreadMXBean.findDeadlockedThreads()调用来实现死锁检测的。ThreadMXBean.findDeadlockedThreads()能够返回一组死锁线程的线程编号。ThreadMXBean类是JMX(Java Management Extension)API的一部分,因此其提供的功能也可以通过jconsole、jvisualvm手工调用。
注意:通过ReentrantLock.lock()申请显式锁的,因此它无法响应中断,也就无法支持死锁的自动恢复。

发生死锁的统一抽象类:

/*** 对哲学家进行抽象** @author Viscent Huang*/
public abstract class AbstractPhilosopher extends Thread implements Philosopher {protected final int id;protected final Chopstick left;protected final Chopstick right;public AbstractPhilosopher(int id, Chopstick left, Chopstick right) {super("Philosopher-" + id);this.id = id;this.left = left;this.right = right;}@Overridepublic void run() {for (;;) {think();eat();}}/** @see io.github.viscent.mtia.ch7.diningphilosophers.Philosopher#eat()*/@Overridepublic abstract void eat();protected void doEat() {Debug.info("%s is eating...%n", this);Tools.randomPause(10);}/** @see io.github.viscent.mtia.ch7.diningphilosophers.Philosopher#think()*/@Overridepublic void think() {Debug.info("%s is thinking...%n", this);Tools.randomPause(10);}@Overridepublic String toString() {return "Philosopher-" + id;}
}

`

公共资源类


/*** 筷子** @author Viscent Huang*/
public class Chopstick {public final int id;private Status status = Status.PUT_DOWN;public static enum Status {PICKED_UP,PUT_DOWN}public Chopstick(int id) {super();this.id = id;}public void pickUp() {status = Status.PICKED_UP;}public void putDown() {status = Status.PUT_DOWN;}public Status getStatus() {return status;}@Overridepublic String toString() {return "chopstick-" + id;}
}

导致死锁的模型


``javapublic class BuggyLckBasedPhilosopher extends AbstractPhilosopher {/*** 为确保每个Chopstick实例有且仅有一个显式锁(而不重复创建)与之对应,<br>* 这里的map必须采用static修饰!*/protected final static ConcurrentMap<Chopstick, ReentrantLock> LOCK_MAP;static {LOCK_MAP = new ConcurrentHashMap<Chopstick, ReentrantLock>();}public BuggyLckBasedPhilosopher(int id, Chopstick left, Chopstick right) {super(id, left, right);// 每个筷子对应一个(唯一)锁实例LOCK_MAP.putIfAbsent(left, new ReentrantLock());LOCK_MAP.putIfAbsent(right, new ReentrantLock());}@Overridepublic void eat() {// 先后拿起左手边和右手边的筷子if (pickUpChopstick(left) && pickUpChopstick(right)) {// 同时拿起两根筷子的时候才能够吃饭try{doEat();} finally {// 放下筷子putDownChopsticks(right, left);}}}//  @SuppressFBWarnings(value = "UL_UNRELEASED_LOCK",
//      justification = "筷子对应的锁由应用自身保障总是能够被释放")protected boolean pickUpChopstick(Chopstick chopstick) {final ReentrantLock lock = LOCK_MAP.get(chopstick);try {lock.lock();Debug.info("%s is picking up %s on his %s...%n",this, chopstick, chopstick == left ? "left" : "right");chopstick.pickUp();}catch (Exception e) {// 不大可能走到这里e.printStackTrace();lock.unlock();return false;}return true;}private void putDownChopsticks(Chopstick chopstick1, Chopstick chopstick2) {try {putDownChopstick(chopstick1);} finally {putDownChopstick(chopstick2);}}protected void putDownChopstick(Chopstick chopstick) {final ReentrantLock lock = LOCK_MAP.get(chopstick);try {Debug.info("%s is putting down %s on his %s...%n",this, chopstick, chopstick == left ? "left" : "right");chopstick.putDown();} finally {lock.unlock();}}
}

模型实现类


public class RecoverablePhilosopher extends BuggyLckBasedPhilosopher {public RecoverablePhilosopher(int id, Chopstick left, Chopstick right) {super(id, left, right);}@Overrideprotected boolean pickUpChopstick(Chopstick chopstick) {final ReentrantLock lock = LOCK_MAP.get(chopstick);try {lock.lockInterruptibly();//这里,pickUpChopstick方法在捕获到lock.lockInterruptibly()抛出的InterruptedException后,主动将当前线程已持有的锁释放掉(即放下当前哲学家已持有的筷子)。利用这个改造后的哲学家模型,我们就可以再现死锁的自动恢复的效果 } catch (InterruptedException e) {// 使当前线程释放其已持有的锁Debug.info("%s detected interrupt.", Thread.currentThread().getName());Chopstick theOtherChopstick = chopstick == left ? right : left;theOtherChopstick.putDown();LOCK_MAP.get(theOtherChopstick).unlock();return false;}try {Debug.info("%s is picking up %s on his %s...%n",this, chopstick, chopstick == left ? "left" : "right");chopstick.pickUp();} catch (Exception e) {// 不大可能走到这里e.printStackTrace();lock.unlock();return false;}return true;}
}

模拟死锁的程序类


public class DiningPhilosopherProblem {public static void main(String[] args) throws Exception {int numOfPhilosopers;numOfPhilosopers = args.length > 0 ? Integer.valueOf(args[0]) : 2;// 创建筷子Chopstick[] chopsticks = new Chopstick[numOfPhilosopers];for (int i = 0; i < numOfPhilosopers; i++) {chopsticks[i] = new Chopstick(i);}String philosopherImplClassName = System.getProperty("x.philo.impl");if (null == philosopherImplClassName) {philosopherImplClassName = "DeadlockingPhilosopher";}Debug.info("Using %s as implementation.", philosopherImplClassName);for (int i = 0; i < numOfPhilosopers; i++) {// 创建哲学家createPhilosopher(philosopherImplClassName, i, chopsticks);}}private static void createPhilosopher(String philosopherImplClassName,int id, Chopstick[] chopsticks) throws Exception {int numOfPhilosopers = chopsticks.length;@SuppressWarnings("unchecked")Class<Philosopher> philosopherClass = (Class<Philosopher>) Class.forName(DiningPhilosopherProblem.class.getPackage().getName() + "."+ philosopherImplClassName);Constructor<Philosopher> constructor = philosopherClass.getConstructor(int.class, Chopstick.class, Chopstick.class);Philosopher philosopher = constructor.newInstance(id, chopsticks[id],chopsticks[(id + 1)% numOfPhilosopers]);philosopher.start();}
}

结果:

死锁的自动恢复有赖于死锁的线程能够响应中断。以上面RecoverablePhilosopher为例,如果我们在代码开发与维护过程中能够意识到它是可能导致死锁的,那么我们应该采取的措施是规避死锁(防患未然)而不是使其支持死锁的自动恢复(为亡羊补牢做准备);相反,如果我们未能事先意识到死锁这个问题,那么这个类的相关方法可能根本无法响应中断,或者能够响应中断但是其响应的结果却未必是DeadlockDetector所期望的——释放其已持有的资源。 其次,自动恢复尝试可能导致新的问题。例如,如果RecoverablePhilosopher(对中断的响应方式是仅仅保留中断标记而并不释放其已持有的资源,即RecoverablePhilosopher.pickUpChopstick方法对InterruptedException异常的处理逻辑仅仅是调用Thread.currentThread().interrupt()以保留中断标记,那么尝试对这样的死锁线程进行恢复非但不能达到预期效果,反而会造成相应线程一直在尝试申请锁而一直无法申请成功,即产生活锁!

Java多线程环境检测系统中是否存在死锁和死锁恢复代码示例相关推荐

  1. Java多线程闲聊(二):活锁和死锁

    Java多线程闲聊(二):活锁和死锁 这两个情况其实都是应该需要避免的情况,为了便于自己的回顾,我还是希望通过尽可能简单的表达来进行简要的归纳. 何谓死锁,就是正正紧紧按照Java的规范进行编程依然会 ...

  2. delay在java中有什么用_DelayQueue怎么在Java多线程并发开发中使用

    DelayQueue怎么在Java多线程并发开发中使用 发布时间:2020-12-05 17:29:31 来源:亿速云 阅读:56 作者:Leah 这篇文章给大家介绍DelayQueue怎么在Java ...

  3. 【源码分析设计模式 5】Java I/O系统中的装饰器模式

    一.基本介绍 动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更有弹性的替代方案. 二.装饰器模式的结构 1.Component,抽象构件 Component是一个接口或者抽象类,是定义我们 ...

  4. python求1到n的乘积_Python如何计算列表中所有数字的乘积?(代码示例)

    在Python中如何将列表中所有数字相乘,然后返回乘积值.下面本篇文章就来给大家介绍三种将列表中的所有数字相乘.计算乘积值的方法,希望对大家有所帮助. 方法一:使用遍历 将变量product的值初始化 ...

  5. python中config命令_Python config.config方法代码示例

    本文整理汇总了Python中config.config方法的典型用法代码示例.如果您正苦于以下问题:Python config.config方法的具体用法?Python config.config怎么 ...

  6. linux下java多线程_Linux系统下Java问题排查——cpu使用率过高或多线程锁问题

    原标题:Linux系统下Java问题排查--cpu使用率过高或多线程锁问题 一个系统.特别是多线程并发的后台系统,在某些特定场景下,可能触发系统中的bug:导致cpu一直居高不下.进程hang了或处理 ...

  7. java 多线程性能_Java中多线程的性能比较

    java 多线程性能 Java中有多种用于多线程的技术. 可以通过同步关键字,锁或原子变量来并行化Java中的一段代码. 这篇文章将比较使用synced关键字ReentrantLock,getAndI ...

  8. Java Platform Module系统中的可选依赖项

    Java平台模块系统(JPMS)对依赖项有很强的见解:默认情况下,需要(必须可访问)它们,然后在编译时和运行时都将它们存在. 但是,这不适用于可选的依赖项,因为代码是针对运行时不一定存在的工件编写的. ...

  9. java死锁业务场景_【深入浅出多线程系列十二】:什么是死锁?(场景+代码示例)...

    在学习Java的道路上,是否路过多线程时总让你很迷惘:很不巧,我也是,而使我们感到很迷惘主要原因都源于没有对概念的深深的理解和实践.所以我决定漫步Java多线程,同你一起会会多线程. 多线程系列 多线 ...

最新文章

  1. Google最新论文:大规模深度推荐模型的特征嵌入问题有解了!
  2. 《我想进大厂》之Spring夺命连环10问
  3. plotly可视化绘制共享坐标轴图
  4. iPhone开发入门守则:Objective-C编码规范--系列教程
  5. wine运行exe程序只出现了一个黑色长方形
  6. 项目管理:软件工程相关知识笔记
  7. BeanUtils的学习
  8. 让LwIP拥有PING其他设备的能力
  9. markdown图片设置
  10. 8 | Spatial-based GNN/convolution模型之GAT(受欢迎)
  11. 计算机一级操作题题库在线,全国计算机一级操作题「题库」
  12. iOS商户进件之【营业执照编号校验】18位社会信用代码验证 unified social credit identifier
  13. 《Head First HTML and CSS 》中英文下载链接
  14. 扰动分析 matlab,扰动材料力学有限元分析:基于MATLAB编程
  15. 年度盘点!Flink 社区全年的精华内容都在这里啦(内附福利)
  16. MFRC522模块开发笔记
  17. (个人学习)资金托管与资金存管的区别
  18. 【柜子设计】草图大师及插件AFU321安装
  19. 2022年江苏省建筑三类人员(项目负责人B证)练习题及答案
  20. 用C实现Lenet的总结

热门文章

  1. 0-1背包动态规划c语言,动态规划解决0-1背包问题程序看不懂,请大家看看帮忙解决下...
  2. 集成android studio,Android Studio集成
  3. python爬虫去哪儿网_大型爬虫案例:爬取去哪儿网
  4. 十一、练习:爬取图虫网付费图片
  5. 十八、前端必学Bootstrap美化(上篇)
  6. 聚类(上)K-mean算法
  7. 转载【IDEA】向IntelliJ IDEA创建的项目导入Jar包的两种方式
  8. 科研实习 | 约翰霍普金斯大学Alan Yuille教授招收计算机视觉暑期科研实习生
  9. ​GPLinker:基于GlobalPointer的实体关系联合抽取
  10. 英国帝国理工出品:SSIM对抗攻击