什么是死锁?
所谓死锁,就是在两个或多个并发进程中,如果每个进程持有某种资源而又都等待着别的进程释放它或它们现在保持着的资源,否则就不能向前推进,此时每个进程都占用了一定的资源但又都不能向前推进,称这一组进程产生了死锁。举个例子,如果此时有一个线程A持有a锁,按照先锁a再获得锁b的的顺序获得锁,而在此同时又有另外一个线程B,
按照先锁b再锁a的顺序获得锁。
死锁产生的原因
- 资源竞争
- 操作系统中的资源分为两类
(1)可剥夺资源,是指某进程在获得这类资源后,该资源可以再被其他进程或系统剥夺,CPU和主存均属于可剥夺性资源;
(2)另一类资源是不可剥夺资源,当系统把这类资源分配给某进程后,再不能强行收回,只能在进程用完后自行释放,如磁带机、打印机等。
- 产生死锁的原因
- 原因一就是竞争不可剥夺资源,例如系统中只有一台打印机,进程A已经占用了打印机,而进程B也要使用打印机,此时B进程就会陷入阻塞;
- 原因二是竞争一些临时性资源(临时资源包括硬件中断、信号、消息、缓冲区内的消息等),通常消息通信顺序进行不当,则会产生死锁。
- 进程间推进顺序非法
例如,进程A在运行过程中请求资源R2,R2已经被B进程占有,A会发送阻塞;当运行进程B时需要请求R1,而R1已经被A占有,于是发生进程死锁。
死锁产生的必要条件
- 互斥条件:
指的是共享资源的互斥。主要是因为多个线程都想访问同一个共享资源,但是该共享资源在某个时刻只能由一个进程访问。
- 持有并等待条件:
某进程持有一些资源并等待另外一些资源,在这一过程中,该进程并不会放弃自己已经持有的资源。
- 不可剥夺条件:
某线程持有的资源在其使用完之前不能被其他线程获取,只能由其自己使用完后释放。
- 循环等待条件:
存在一个进程链,每个进程占有下一个进程所需要的至少一种资源。
死锁的解决方法
简单描述(四种方法):
- 预防:通过设置某些限制条件,以破坏产生死锁的四个条件中的一个或者几个,来防止发生死锁。
- 避免:系统在分配资源时根据资源的使用情况提前作出预测,从而避免死锁的发生。
- 检测:允许系统在运行的过程中产生死锁,但是,系统中有相应的管理模块可以及时检测出已经产生的死锁,并且精确地确定与死锁有关的进程和资源,然
- 后采取适当措施,清除系统中已经产生的死锁。
- 解除:与检测死锁相配套的一种措施,用于将进程从死锁状态下解脱出来。
解决死锁的具体描述:
预防死锁
根据死锁产生的四个必要条件,只要使用其中之一不能成立,死锁就不会出现。但必要条件①是由设备的固有特性所决定的,不仅不能改变,相反还应加以保证,因此实际上只有三种方法:
- 资源一次性分配:一次性分配所有资源,这样就不会再有请求了,只要有一个资源得不到分配,也不给这个进程分配其他的资源:(破坏请求条件)
- 可剥夺资源:即当某进程获得了部分资源,一但得不到其它资源,则释放已占有的资源(破坏不可剥夺条件)
- 资源有序分配法:系统给每类资源赋予一个编号,每一个进程按编号递增的顺序请求资源,释放则相反(破坏环路等待条件)
避免死锁
避免死锁,它是在进程请求分配资源时,采用某种算法(银行家算法)来预防可能发生的死锁,从而拒绝可能引起死锁的某个资源请求。
- 在避免死锁(或银行家算法)中必须谈到两种系统状态:
安全状态,指系统能按照某种顺序,为每个进程分配所需的资源,直至最大需求,使得每个进程都能顺利完成。
非安全状态:即在某个时刻系统中不存在一个安全序列,则称系统处于不安全状态或非安全状态。
虽然并非所有不安全状态都是死锁状态,但当系统进入不安全状态后,便有可能进入死锁状态;反之只要系统处于安全状态,系统便可避免进入死锁状态。因此,避免死锁的实质是如何使系统不进入不安全状态。
检测死锁
通过使用软件工具来检测死锁:### 示例代码
package com.yyl.one.lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author yangyuanliang
* @version 1.9
* @date 2025/1/25 11:27
*/
public class DealLockTest {
private static Object lockA =new Object();
private static Object lockB =new Object();
public static void alock(){
synchronized (lockA){
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lockB){
System.out.println("get lock b");
}
}
}
public static void block(){
synchronized (lockB){
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lockA){
System.out.println("get lock b");
}
}
}
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
alock();
}
});
thread.setName("my thread 1 ....");
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
block();
}
});
thread2.setName("my thread 2 ....");
thread.start();
thread2.start();
}
}
java 死锁检查
命令jstack pid就能查到死锁的线程
Found one Java-level deadlock:
=============================
"my thread 2 ....":
waiting to lock monitor 0x00007f925580ba18 (object 0x000000079575cfd0, a java.lang.Object),
which is held by "my thread 1 ...."
"my thread 1 ....":
waiting to lock monitor 0x00007f925580e2a8 (object 0x000000079575cfe0, a java.lang.Object),
which is held by "my thread 2 ...."
Java stack information for the threads listed above:
===================================================
"my thread 2 ....":
at com.yyl.one.lock.DealLockTest.block(DealLockTest.java:35)
- waiting to lock <0x000000079575cfd0> (a java.lang.Object)
- locked <0x000000079575cfe0> (a java.lang.Object)
at com.yyl.one.lock.DealLockTest$2.run(DealLockTest.java:53)
at java.lang.Thread.run(Thread.java:748)
"my thread 1 ....":
at com.yyl.one.lock.DealLockTest.alock(DealLockTest.java:21)
- waiting to lock <0x000000079575cfe0> (a java.lang.Object)
- locked <0x000000079575cfd0> (a java.lang.Object)
at com.yyl.one.lock.DealLockTest$1.run(DealLockTest.java:45)
at java.lang.Thread.run(Thread.java:748)
Found 1 deadlock.
2万+

被折叠的 条评论
为什么被折叠?



