回答
死锁指的是两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,如果没有外力的帮助下,它们都将无法推进下去。简单的说就是两个或以上的进程都在互相等待对方释放资源,但是它们谁都不释放进程,系统就卡住了。
解决死锁的方法主要有以下几种:
- 以确定的顺序获得锁:在获取锁的顺序上进行控制,确保所有线程获取锁的顺序是一致的,这样就可以预防死锁的产生。
- 超时放弃:在获取锁的时候设置超时时间,如果在指定时间内未获取锁,我们可以做其他操作,避免死锁。比如使用
ReentrantLock
的tryLock()
。 - 监控和检测:使用一些死锁检测工具来检测线程是否发生了死锁,如果发现死锁,我们可以采取一些必要的措施,比如中断其中一个线程。
- 避免嵌套锁:尽量避免一个线程同时持有多把锁
扩展
死锁演示
产生死锁有四个必要条件:
- 互斥条件:一个资源每次只能被一个进程使用。
- 占有并等待条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
- 不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺,只能由该进程自己释放。
- 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
举一个例子:
public class DeadlockTest {
private static final Object resourceA = new Object();
private static final Object resourceB = new Object();
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
synchronized (resourceA) {
System.out.println(Thread.currentThread().getName() + "获取【资源 A】");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
synchronized (resourceB) {
System.out.println(Thread.currentThread().getName() + "获取【资源 B】");
}
}
});
Thread thread2 = new Thread(() -> {
synchronized (resourceB) {
System.out.println(Thread.currentThread().getName() + "获取【资源 B】");
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (resourceA) {
System.out.println(Thread.currentThread().getName() + "获取【资源 A】");
}
}
});
thread1.start();
thread2.start();
}
}
Thread-0
先锁住 resourceA
,然后等待 resourceB
,Thread-1
先锁住 resource
B,然后等待 resourceA
,两个线程都在等待对方释放锁,然后他们就进入死锁状态了。
死锁排查
排查死锁的方式有几种,大明哥一般都是直接使用 jstack 命令。
使用 jstack 命令排查死锁
首先,利用 jps
拿到当前 Java 应用程序的 pid
。
使用命令 jstack -l 42242
,我们可以得到如下信息:
这图以一种非常清晰的方式告诉你,Thread-0
在等待哪个锁资源,这个资源被哪个线程持有,Thread-1
在等待哪个锁资源,这个资源被哪个线程持有。一目了然!!
当然,我们还可以使用其他的方式来检测、查看死锁,比如Java VisualVM
,不过在实际应用过程中,jstack
完全够用了。
Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。
它的内容包括:
- 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
- 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
- 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
- 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
- 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
- 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
- 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
- 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw
目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:
想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询
同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。