死锁应该可以说是并发编程中比较常见的一种情况,可以说如果程序产生了死锁那将会对程序带来致命的影响;所以排查定位、修复死锁至关重要;

  我们都知道死锁是由于多个对象或多个线程之间相互需要对方锁持有的锁而又没有释放对方所持有的锁,导致双方都永久处于阻塞状态

  如上图所示,线程1持有对象1的锁、线程2持有对象2的锁,持此线程1又想去获取对象2对象锁、线程2想获取对象1对象锁,此时由于双方都没有获取到想要的锁,任务没完成所以也没释放锁,导致一直僵持呢,于是阻塞、产生死锁;

死锁检测

  需要检测死锁肯定要先有死锁出现,下面的demo模拟了一个死锁的产生;

  1. public class DeadlockDemo extends Thread {
  2. private BaseObj first;
  3. private BaseObj second;
  4. public DeadlockDemo(String name, BaseObj first, BaseObj second) {
  5. super(name);
  6. this.first = first;
  7. this.second = second;
  8. }
  9. public void reentrantLock() throws InterruptedException {
  10. first.lock();
  11. System.out.println(String.format("%s 持有:%s 对象锁,等待获取:%s对象锁", this.getName(), first, second));
  12. second.lock();
  13. first.unlock();
  14. second.unlock();
  15. }
  16. @Override
  17. public void run() {
  18. try {
  19. reentrantLock();
  20. } catch (Exception e) {
  21. e.printStackTrace();
  22. }
  23. }
  24. public static void main(String[] args) throws InterruptedException {
  25. ObjOne one = new ObjOne();
  26. ObjTwo two = new ObjTwo();
  27. DeadlockDemo thread1 = new DeadlockDemo("Thread1", one, two);
  28. DeadlockDemo thread2 = new DeadlockDemo("Thread2", two, one);
  29. thread1.start();
  30. thread2.start();
  31. thread1.join();
  32. thread2.join();
  33. }
  34. }

  运行上面的demo将看到程序被阻塞了,没法结束运行;只看到如下运行结果:

Thread1 持有:objOne 对象锁,等待获取:objTwo对象锁 Thread2 持有:objTwo 对象锁,等待获取:objOne对象锁

  这demo没法结束运行就是由于产生了死锁,两个线程都在相互对待获取对方所持有的对象锁;

  这时候要解决问题就需要找出哪里出现了死锁,通过代码走查通常不容易发现死锁,当然我们这程序很容易发现,因为我们刻意产生的死锁;所以就需要工具来检测死锁,这里可用的工具主要有:jconsole、jvisualvm、jstack等,这些工具其实都是jdk自带的,用法都很类似;

  这里使用jvisualvm来检测当前的demo程序是否产生了死锁;打开jvisualvm连接到当前的应用程序即可看到程序的监控信息,如内存、CPU、性能、GC等等;打开进入线程的tab项查看程序的线程信息,这里很明显的就看到了提示该程序被检测除了死锁!

  点击 线程Dump可以看到线程的堆栈信息,从中可以看到线程的详细信息,并定位死锁;



  从上图可以看到线程产生死锁的原因,Thrad2是等待Thread1、Thread1是等待Thread1, 从下图的堆栈信息即可定位死锁产生的位置;

死锁扫描

  除了发现程序出现问题后我们去扫描死锁外,我们还可以实时的去扫描程序用于发现程序中是否存在死锁;

  JDK提供了MXBean Api可用于扫描程序是否存在死锁,ThreadMXBean提供了findDeadlockedThreads()方法,可以用于找到产生死锁的线程;这里在上面的demo程序中添加一个方法用于扫描死锁,虽然这种方法可以扫描到死锁但是由于每次都对线程打快照对程序性能会有比较大的影响,所以慎用;

  1. public static void scanDeadLock() {
  2. ThreadMXBean mxBean = ManagementFactory.getThreadMXBean();
  3. Runnable runnable = () -> {
  4. long[] ids = mxBean.findDeadlockedThreads();
  5. System.out.println("扫描死锁...");
  6. if (ids != null) {
  7. ThreadInfo[] threadInfos = mxBean.getThreadInfo(ids);
  8. for (ThreadInfo threadInfo : threadInfos) {
  9. System.out.println(threadInfo);
  10. }
  11. }
  12. };
  13. ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(5, Executors.defaultThreadFactory());
  14. executorService.scheduleAtFixedRate(runnable, 1, 5, TimeUnit.SECONDS);
  15. }

避免死锁

  解决死锁最好的方法就是避免死锁了,比如上面的demo我们可以把直接使用无参数的lock()方法换为使用tryLock方法,tryLock还可以指定获取锁超时时间,到了超时时间还没获得到锁就会放弃获取锁,当然还有其它方法可以避免死锁;

  1、避免使用多个锁、长时间持有锁;

  2、设计好多个锁的获取顺序

  3、使用带超时的获取锁方法

文章首发地址:Solinx

http://www.solinx.co/archives/1196

Java中死锁的定位与修复的更多相关文章

  1. 关于java中死锁的总结

    关于死锁,估计很多程序员都碰到过,并且有时候这种情况出现之后的问题也不是非常好排查,下面整理的就是自己对死锁的认识,以及通过一个简单的例子来来接死锁的发生,自己是做python开发的,但是对于死锁的理 ...

  2. Java中死锁的简单例子及其避免

    死锁:当一个线程永远地持有一个锁,并且其他线程都尝试获得这个锁时,那么它们将永远被阻塞.比如,线程1已经持有了A锁并想要获得B锁的同时,线程2持有B锁并尝试获取A锁,那么这两个线程将永远地等待下去. ...

  3. 浅谈java中死锁问题

    知识点:死锁的产生.死锁的实例 一:死锁的产生 我们在解决多线程共享资源的线程同步问题时,会使用synchronized关键字修饰方法或者通过Lock加锁方式修饰方法.代码块,防止多个线程访问统一资源 ...

  4. JAVA中关于同步与死锁的问题

    java中当多个现成同时操纵同一资源的时候需要考虑同步的问题.如车站售票,不同售票点卖同一班次车票的时候就要同步,否则卖票会有问题.下面代码模拟车站卖票: class TicketSeller imp ...

  5. java多线程--死锁

    1. Java中导致死锁的原因 Java中死锁最简单的情况是,一个线程T1持有锁L1并且申请获得锁L2,而另一个线程T2持有锁L2并且申请获得锁L1,因为默认的锁申请操作都是阻塞的,所以线程T1和T2 ...

  6. java之死锁

    转载自 https://www.cnblogs.com/xiaoxi/p/8311034.html 一.死锁的定义 多线程以及多进程改善了系统资源的利用率并提高了系统 的处理能力.然而,并发执行也带来 ...

  7. Java:死锁编码及定位分析

    Java:死锁编码及定位分析 本笔记是根据bilibili上 尚硅谷 的课程 Java大厂面试题第二季 而做的笔记 概念 死锁是指两个或多个以上的进程在执行过程中,因争夺资源而造成一种互相等待的现象, ...

  8. 死锁线程探讨Java中的死锁现象

    题记:写这篇博客要主是加深自己对死锁线程的认识和总结实现算法时的一些验经和训教,如果有错误请指出,万分感谢. 今天搞了一下Java的死锁机制,感到自己还是不怎么懂,所以就从一些简略的源代码中琢磨:我先 ...

  9. java中xxe漏洞修复方法

    java中禁止外部实体引用的设置方法不止一种,这样就导致有些开发者修复的时候采用的错误的方法 之所以写这篇文章是有原因的!最早是有朋友在群里发了如下一个pdf, 而当时已经是2019年1月末了,应该不 ...

随机推荐

  1. SpringSecurity在Springboot下使用的初步体验

    SpringSecurity曾经在十年前非常火热,只要是做权限系统,当时几乎非用它不可,记得是在XML文件里一堆的配置.曾几何时,Shiro冒了出来,以其简洁和轻量的风格慢慢地捕获了众多码农的心,从此 ...

  2. zabbix监控ssl证书到期时间

    监控脚本 cat ssl_check.sh #!/bin/bash # #获取ssl证书的过期时间 #menghao #获取证书的有效时间 time=$(echo | openssl s_client ...

  3. jquery.form插件 提交表单 type="hidden"取不到值的问题记录

    1.外国文献:说可以改成其他的(非hidden),再加style="display:none"隐藏. <INPUT type="password" sty ...

  4. 共有49款Windows GUI开发框架开源软件 【转】

    源文 : http://www.oschina.net/project/tag/178/gui?lang=36&os=0&sort=view&p=1 桌面应用开发引擎 Allo ...

  5. 面向对象之组合VS继承:继承过时了?

        在阅读Effective Java中的第16条时发现了一个有趣的机制或者说是模式,那就是组合(文中翻译为复用,但是作者认为组合更能体现这种模式的精神),并且文中建议使用组合.  那什么是组合, ...

  6. asp.net core 发布到iis session无法传递的问题

    网站是用asp.net core 的Razor Pages开发的,其中用户登录用到了session,调试运行没有问题,但是发布到iis之后出现session无法记录的问题. 我用log记录查看了一下, ...

  7. vue中npm run dev运行项目自动打开浏览器

    npm run dev运行项目自动打开浏览器设置自动打开浏览器 // 各种设备设置信息      host: 'localhost', //主机名      port: 8080, // 端口号(默认 ...

  8. 【python】使用flask制作小型页面的关键点总结

    目录结构 app.py web代码 store.db 存储信息的轻量数据库,用的sqlite3 schema.sql 数据库的初始化建表语句 settings.cfg 配置信息 static/styl ...

  9. python3 集合(set)

    一.定义:集合是一个无序不重复元素序列 语法: #---------------两种写法-------------------------# parame = {value1,value2,value ...

  10. mysql 服务器负载过高的解决分析之路

    最近我们有台 mysql 服务器一直报负载过高,不停的收到阿里云的报警短信,让我很抓狂,登陆上服务器,看下一下,慢查询日志 发现有60多万的慢查询日志,一看这个就知道是搜索带来的,一直想把搜索的服务给 ...