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

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

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

死锁检测

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

 public class DeadlockDemo extends Thread {
private BaseObj first;
private BaseObj second; public DeadlockDemo(String name, BaseObj first, BaseObj second) {
super(name);
this.first = first;
this.second = second;
} public void reentrantLock() throws InterruptedException {
first.lock();
System.out.println(String.format("%s 持有:%s 对象锁,等待获取:%s对象锁", this.getName(), first, second));
second.lock();
first.unlock();
second.unlock();
}
@Override
public void run() {
try {
reentrantLock();
} catch (Exception e) {
e.printStackTrace();
}
} public static void main(String[] args) throws InterruptedException {
ObjOne one = new ObjOne();
ObjTwo two = new ObjTwo(); DeadlockDemo thread1 = new DeadlockDemo("Thread1", one, two);
DeadlockDemo thread2 = new DeadlockDemo("Thread2", two, one); thread1.start();
thread2.start(); thread1.join();
thread2.join();
}
}

  运行上面的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程序中添加一个方法用于扫描死锁,虽然这种方法可以扫描到死锁但是由于每次都对线程打快照对程序性能会有比较大的影响,所以慎用;

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

避免死锁

  解决死锁最好的方法就是避免死锁了,比如上面的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. 【7】学习C++之类的构造函数

    (说实话,我一开始真没觉得构造函数这块有多重要,但是看的视频中老师却花了不少的时间去讲这块内容,本着整理了不亏的心态还是整理了一下) 1.常见的构造函数 C++的类在创建对象的时候,都会去调用构造函数 ...

  2. [经验交流] kubernetes v1.11 更新了高可用方案

    kubernetes v1.11已经发布了一段时间,和以前相比,一个显著亮点是更新了高可用方案: https://kubernetes.io/docs/setup/independent/high-a ...

  3. python3随机数函数

    随机数函数 choice(seq) 从序列的元素中随机挑选一个元素,比如random.choice(range(10)),从0到9中随机挑选一个整数. randrange ([start,] stop ...

  4. 防盗链之URL参数签名

    一.概述 传统的 IP 禁用.referer 防盗链.User-Agent 防盗链.地区访问控制等防盗链措施已经无法完全满足用户要求,所以开发出URL参数签名方式来防盗链 二.实现 Token防盗链是 ...

  5. 使用Mermaid画图

    流程图的示例 时序图的示例 甘特图的示例 FAQ 很多时候,你想解释自己的想法/代码,但是用语言来表达会很啰嗦,并且读者也不易理解.一般这种情况下,我们都会想使用图解来解释.但是,我们也不会想下载那些 ...

  6. .Net 入门资料推荐 (编辑中)

    1.首先推荐 网易云课堂上的一个付费课程:常老师带你学ASP.NET MVC ,价格199元 2. 一个.net的框架,ABP,中文介绍如下 http://www.cnblogs.com/farb/p ...

  7. GitLab CI/CD 进行持续集成

    简介 从 GitLab 8.0 开始,GitLab CI 就已经集成在 GitLab 中,我们只要在项目中添加一个 .gitlab-ci.yml 文件,然后添加一个 Runner,即可进行持续集成. ...

  8. git自动部署到服务器

    1.现在服务器配置空仓库 mkdir -p test/project.git chmod 777 test cd test/project.git/ git init --bare . cd .. c ...

  9. 使用gethostname()函数和gethostbyname()函数获取主机相关信息

    gethostname() : 返回本地主机的标准主机名. 原型如下: #include <unistd.h> int gethostname(char *name, size_t len ...

  10. thymleaf th:if判断某值不为空

    简单描述:判断后台传递过来的值,是否为空,来做一些业务上的处理. 代码: <div class="col-md-6" th:if="${not #strings.i ...