实验一:资源分配仿真
实目的
在课程已经学习了死锁的4个必要条件的基础上,为了了解系统的资源分配情况,假定系统中任一资源在每一时刻只能由一个进程使用,任何进程不能抢占其它进程正在占有的资源,当进程得不到资源时,必须等待。因此,只要资源分配策略能保证不出现循环等待,系统就不会发生死锁。
要求学生编写和调试系统动态分配资源的仿真程序,观察死锁产生的条件,再采用适当的算法,有效地防止和避免死锁发生。
PS:实体类使用lombox自动生成getter setter 有参 无参方法(没有的手动生成)
lombox maven仓库地址
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
实现方式
随机分配算法产生死锁,银行家算法避免死锁
具体代码
随机分配算法:此算法不是模拟死锁而是会真正产生死锁(多运行几次随机的有的时候不会产生死锁)
package com.xu.demo.ytu.bank;
import java.util.ArrayList;
import java.util.List;
public class RandomAgl {
public static Object A=new Object();
public static Object B=new Object();
public static Object C=new Object();
public static Object D=new Object();
public static void RanDomTest(List<Object> list){
System.out.println(list);
new Thread(()->{
synchronized (A){
System.out.println(Thread.currentThread().getName()+"我得到了资源:"+A);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Object O=list.get((int) (Math.random() * 4));
System.out.println("随机分配资源开始:线程"+Thread.currentThread().getName()+"随机去获取的资源是"+O);
synchronized (O){
System.out.println("线程"+Thread.currentThread().getName()+"得到了资源"+O);
}
}
}).start();
new Thread(()->{
Object O=list.get((int) (Math.random() * 4));
synchronized (B){
System.out.println(Thread.currentThread().getName()+"我得到了资源:"+B);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("随机分配资源开始:线程"+Thread.currentThread().getName()+"随机去获取的资源是"+O);
synchronized (O){
System.out.println("线程"+Thread.currentThread().getName()+"得到了资源"+O);
}
}
}).start();
}
public static void main(String[] args) {
List<Object> testList=new ArrayList<>();
testList.add(A);
testList.add(B);
testList.add(C);
testList.add(D);
RandomAgl.RanDomTest(testList);
}
}
运行截图
死锁已经产生,接下来进入java的bin目录具体查看
可以看出,线程1得到了资源270ca0并且想要去获取资源270c90,线程0得到了资源270c90并且想要获取资源270ca0死锁产生
银行家算法:
PCB类
package com.xu.demo.ytu.bank;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PCB {
String processName;
int maxUsed;
int alreadyUsed;
boolean isFinish;
@Override
public String toString() {
return
"\t"+processName +
" \t" + maxUsed +
" \t" + alreadyUsed +
" \t" +(maxUsed-alreadyUsed)+
" \t" + isFinish ;
}
}
BankAlg
package com.xu.demo.ytu.bank;
import java.util.*;
public class BankAlg {
public static int availableSource = 10;
public static ArrayList<String> safeList = new ArrayList<>();
public static Map<String, PCB> pcbMap = new LinkedHashMap<>();
/**
* 初始化操作
*/
public static void init() {
PCB a = new PCB("A", 5, 1, false);
PCB b = new PCB("B", 3, 1, false);
PCB c = new PCB("C", 4, 2, false);
PCB d = new PCB("D", 6, 3, false);
pcbMap.put(a.processName, a);
pcbMap.put(b.processName, b);
pcbMap.put(c.processName, c);
pcbMap.put(d.processName, d);
System.out.println("---------------------------------------初始化--------------------------------------------------");
System.out.println("进程名 " + "最大需求量 " + "占有量 " + " 仍需 " + " 完成");
pcbMap.forEach((k, v) -> {
System.out.println(v);
});
pcbMap.forEach((k, v) -> {
availableSource -= v.alreadyUsed;
});
System.out.println("剩余资源量:" + availableSource);
}
/**
*安全性检测算法
*/
public static void safe(String pName, int pNum) {
//请求的资源大于剩余资源,请求不安全,拒绝分配
if (availableSource < pNum) {
System.out.println("请求不安全 拒绝分配");
} else {
//尝试分配
availableSource = availableSource - pNum;
pcbMap.get(pName).alreadyUsed += pNum;
//仍需资源如果为0,表明进程请求资源结束,进程释放资源
if (pcbMap.get(pName).maxUsed - pcbMap.get(pName).alreadyUsed == 0) {
availableSource += pcbMap.get(pName).maxUsed;
pcbMap.get(pName).isFinish = true;
pcbMap.get(pName).maxUsed = pcbMap.get(pName).alreadyUsed = 0;
}
//添加安全序列
pcbMap.forEach((k, v) -> {
if (v.maxUsed - v.alreadyUsed <= availableSource && !v.isFinish) {
safeList.add(k);
}
});
//如果安全队列没有满,就说明当前分配资源可能不安全,继续尝试
//找不到安全序列,拒绝请求
if (safeList.size() == 0) {
List<Boolean> checkList = new ArrayList<>();
pcbMap.forEach((k, v) -> {
checkList.add(v.isFinish);
});
//如果安全序列全部完成不进行撤销
System.out.println("请求不安全 拒绝分配");
availableSource = availableSource + pNum;
pcbMap.get(pName).alreadyUsed -= pNum;
//这种情况比较特殊这时候对最后一个进程完成分配
if (!checkList.contains(false)) {
availableSource = availableSource - pNum;
pcbMap.get(pName).alreadyUsed += pNum;
}
}
//继续尝试分配
int temp = 0;
for (String s : safeList) {
//在已经添加到安全序列的进程