一. 要求
<1>.有录入界面动态录入进程数,资源种类数,各类资源总数,t0时刻各进程的最大需求数,已分配数等信息.
<2>.有算法选择界面,能够进行安全性检验,对进程动态请求资源的银行家算法检查,退出等的功能选择,要求可以进行多进程多次的资源请求.
<3>.有输出界面,要求能够输出安全性检查的结果,如安全能够输出安全序列,能够输出进程请求资源后是否分配的结果,若不能分配要输出原因,如果能够分配,要输出分配后进程及资源的状态.
二 …初始化
这个银行家算法我的思想就是用数组去写,不用太麻烦,直接数组整起再去填值就OK了,
<1>.先去初始化资源总数和进程总数.
<2>.有了这2个数,不是所有的二维数组和一维数组的长度就定了.
<3>.后来去给 maxNeed[][](t0时刻最大资源总数),possess[][](已分配资源数),还有
resources[](各类资源总数)这些数组赋值,去计算available[](可利用资源),need[][](进程所需要资源数).这样基本上就OK了
<4>我还定义了一个availableTrue[][]这个二维数组,就是在利用available[]这个一维数组每次计算把available + possess的值赋给availableTrue[][],来保存.其实availableTrue[][]是书上的work + Allocation
<5>.还有finish[](当前状态),securitySequence[](安全队列)一并初始化,其余的4个数据成员变量是我的动态输入必需品,随意的.
三 . 安全性检验
如果存在一个由系统中所有进程构成的安全序列P1,…,Pn,则系统处于安全状态。安全状态一定是没有死锁发生。
我的思想先设置一个判断器和计数器.
计数器:先来个变量来记下遍历一次need[][]数组之前的计数器值,遍历一遍后,
<1>.如果计数器值与之前记录变量相等并且计数器值小于进程总数,那就是卡住了,就不安全直接返回,输出不安全队列.
<2>.如果不等于并且计数器值小于进程总数就继续.如果不等于并且等于进程总数,就安全了输出安全队列.
判断器:在第二个for循环去遍历该进程资源数是否小于可利用资源数,小于就判断通过直接去回收,不小于就直接下一个进程.
就是去遍历need二维数组运用这俩个就可以简单的输出安全和不安全,之后再安全和不安全返回之前得把available[],finish[]和securitySequence[]数组置为初始值.就可以连续检验并在银行家算法中调用.
这个方法为boolean类型是为了银行家算法中调用,在过程中记录第一个进入安全序列的进程下标是为了返回available的初值,在这个方法中其他变量基本上都是为了动态输入.
四. 银行家算法
银行家算法(Banker’s Algorithm)是一个避免死锁(Deadlock)的著名算法,是由艾兹格·迪杰斯特拉在1965年为T.H.E系统设计的一种避免死锁产生的算法。它以银行借贷系统的分配策略为基础,判断并保证系统的安全运行。
我的思想是开始不得先输入你要请求的进程是哪个,然后初始化请求数组去存入你输得各个资源数.然后就可以分为3步了.
<1>.去判断他请求的资源是否小于他这个进程的need资源,小于就可以进行第二步,大于就返回该请求无法通过该进程的需求(need)检验.
<2>.再去判断他请求资源是否小于现有的可利用资源available,小于就进行第三步,大于就返回该请求无法通过可利用资源数(available)的需求检验.
<3>.在第二步之后就得去修改这个进程的need资源数和possess已分配资源数,还有现有分配资源数available,同时还得保存这3个修改值之前的值.这时候又得2步(安全或不安全):
(1).安全:直接按修改的值去调用安全性检验算法.同时在这里要注意一个问题就是请求过后他的need被修改为0 0 0 了 ,这时候就应该进程回收把他的possess 也置为 0 0 0,这就是在安全性检验中回收里面的那个if里的代码.
(2)不安全:就得把之前保存的修改之前的值全赋回去.就完了.
五. 动态输出(可有可无)
这个print()是实现动态输出的,纯属弄这好看,就是用count1记录当前回收了几个进程,就直接输出几个.用了进程睡眠(Thread.sleep())让主进程等待1.5秒.
六. 一些感悟
<1>. 数组写这个还是太生硬了,不太灵活想实现一些东西就得定义全局变量才能实现,我觉得用对象去写应该要灵活好多.
<2>.写代码之前注释很重要,写了注释就直接往里填代码就OK了.
<3>.界面很重要,我这个界面太low了.
七. 具体代码
注释很多,不加讲解了.
import java.util.Arrays;
import java.util.Scanner;
public class BankOperation {
public int resourceType; //资源种类
public int process; //进程个数
public int[][] maxNeed; //t0时刻各进程的最大需求数
public int[][] possess; //每个进程的资源已分配数
public int[][] need; //每个进程的资源需要数
public int[] resources; //各类资源总数
public int[] available; //可利用资源数
public boolean[] finish; //判断进程是否可被安全
public int[] securitySequence; //安全序列
public int[][] availableTrue; //实际的可利用资源数.
public int count1 = 0; //去记录他几个进程进来了.
public boolean judgement = false; //这是判断到底是银行家算法还是安全性检验进行的检验.
public int index = 0; //银行家算法请求的进程
public boolean min = false; //动态输出的必需品
public void Init(){ //初始化
Scanner scanner = new Scanner(System.in);
//资源初始化
System.out.println("请你输入你的资源种类");
resourceType = scanner.nextInt();
//去具体初始化各类资源数
resources = new int[resourceType];
System.out.println("请你输入这" +resourceType+ "类资源的具体值");
for(int i = 0; i < resourceType; i++){
System.out.println("请你输入第" +i+ "类资源总数");
resources[i] = scanner.nextInt();
}
//进程初始化
System.out.println("请你输入你的进程总数");
process = scanner.nextInt();
//可以去初始化各个二维数组的空间大小了
maxNeed = new int[process][resourceType];
possess = new int[process][resourceType];
need = new int[process][resourceType];
availableTrue = new int[process][resourceType];
//给t0时刻个进程需求数赋值
System.out.println("请你给t0时刻各进程去赋资源数");
assignment(maxNeed);
//给各个进程已分配数组赋值
System.out.println("请你给各进程已分配资源数赋值");
assignment(possess);
//去求个进程的需求数组
for(int i = 0; i < need.length; i++){
for(int j = 0; j < need[i].length; j++){
need[i][j] = maxNeed[i][j] - possess[i][j];
}
}
//去初始化一下可利用资源数,去遍历已分配数组,用总数一减就OK了.
int row = possess.length;
int col = possess[0].length;
available = new int[resourceType];
for(int i = 0; i < col; i++){
int sum = 0; //记录那一列之和
for(int j = 0; j < row; j++){
sum += possess[j][i];
}
available[i] = resources[i] - sum;
availableTrue[0][i] = available[i]; //给实际的可利用数组赋值.
}
//去初始化一下boolean数组,初值为false不用管
finish = new boolean[process];
//去初始化一下安全序列,全为666预防0那个.
securitySequence = new int[process];
for(int i = 0; i < securitySequence.length; i++){
securitySequence[i] = 666;
}
}
public void assignment(int[][] tem){
Scanner scanner = new Scanner(System.in);
for(int i = 0; i < tem.length; i++){
System.out.println("请你给第" +i+ "进程赋值");
for(int j = 0; j < tem[i].length; j++){
tem[i][j] = scanner.nextInt();
}
}
}
public boolean SafetyInspection(){ //安全性检验
int count = 0; //用来记录进程数.和遍历一遍看有无改变.
boolean judge = false; //再进程每行判断起作用
int index1 = 0; //去记录一下第一次安全队列执行的哪一个下标.
//去遍历需求数组,如果可利用的资源数大于等于某个进程的需求数,就回收.
// 否则继续遍历,这时候就看count与finish数组了.
while(true){
int tem = count; //记录一下开始进程数.
for(int i = 0; i < need.length; i++){
judge = false; //每次都需要布置初始值
for(int j = 0; j < need[0].length; j++){
//去判断
if(finish[i] == true || available[j] < need[i][j]){
judge = true;
break; //是true就没必要在继续了.因为一个小了,其他无所谓
}
}
if(judge == false){ //回收
for (int z = 0; z < possess[i].length; z++) {
available[z] += possess[i][z];
availableTrue[i][z] = available[z]; //给实际的可利用数组赋值.
}
if(index == i && judgement == true) { //这是need为0的进程 需要被回收.
boolean gg = false;
for (int v = 0; v < need[i].length; v++) {
if (need[i][v] != 0) {
gg = true;
}
}
if (gg == false) { //全为0要被回收.
for (int v = 0; v < need[i].length; v++) {
possess[i][v] = 0;
}
}
judgement = false; //用完置为原值.
}
finish[i] = true; //置true
securitySequence[count] = i; //更新安全序列
count += 1; //每次循环完有进程被回收就加1.
count1 += 1;
//来个输出的过2秒输一下.
try {
Thread.sleep(1500);//括号里面的5000代表5000毫秒,也就是5秒,可以该成你需要的时间
print();
} catch (InterruptedException e) {
e.printStackTrace();
}
if(count == 1){ //记录第一个进入安全队列的.
index1 = i;
}
}
}
if(count == process){ //完成完之后,其余值不变,把假的可利用值赋回来.
System.out.print("该作业安全,你的安全序列为: ");
System.out.println(Arrays.toString(securitySequence));
//把假的可分配资源数置为初始值.
for(int i = 0; i < availableTrue[0].length; i++){
available[i] = availableTrue[index1][i] - possess[index1][i];
}
//把finish数组置为初始值
for(int i = 0; i < finish.length; i++){
finish[i] = false;
}
//安全队列也得重新赋回初值,要不我的不安全队列就不行了.
for(int i = 0; i < securitySequence.length; i++){
securitySequence[i] = 666;
}
count1 = 0; //动态输入每次安全系列弄完就得置为0.
min = false;
return true;
}
//在一次循环之后,如果count值没有改变,则就没有进程要求被满足,就应该break,不安全.
if(count == tem && count < process){
int[] nosafe = new int[process];
int j;
int count11 = 0;
System.out.println("不安全,因为这几个序列中需求不被满足");
for(int i = 0; i < securitySequence.length; i++){
for(j = 0; j < securitySequence.length; j++){
if(i == securitySequence[j]){ //安全序列数值肯定是 0 ~ process里这些数,所以直接去遍历安全序列数组,谁没有谁不安全.
break;
}
}
if(j >= securitySequence.length){
nosafe[count11] = i; //不安全的全存在nosafe数组中
}
}
for (int i = 0; i < count11; i++){
System.out.print(" " + nosafe[i]);
}
//2.把所有值都赋值为原来的部分.
//把初始值赋回来.
for(int i = 0; i < availableTrue[0].length; i++){
available[i] = availableTrue[index1][i] - possess[index1][i]; //找到第一次进安全序列的进程
// ,然后直接求出开始的可分配资源.
}
//把finish数组中执行过的数组置为false
for(int i = 0; i < finish.length; i++){
finish[i] = false;
}
//安全队列也得重新赋回初值,要不我的不安全队列就不行了.
for(int i = 0; i < securitySequence.length; i++){
securitySequence[i] = 666;
}
count1 = 0; //动态输入每次安全系列弄完就得置为0.
min = false;
return false;
}
}
}
public boolean ResourceRequest(){ //资源性请求
min = false;
//如果你的检验通过了,但是没有安全序列,则不能修改这个数组
int[][] temporary = new int[3][resourceType]; //去存请求的那个最初的需求和最初的占有和最初的可分配资源
Scanner scanner = new Scanner(System.in);
System.out.println("请输入你要给几号进程请求");
index = scanner.nextInt();
int[] request = new int[resourceType];
System.out.println("请输入你的请求资源数");
for(int i = 0; i < request.length; i++){
request[i] = scanner.nextInt();
}
//去进行资源校验,继续设置判断器.
boolean judge = false; //为true就通过.
//1.和该进程的请求去校验.
for(int i = 0; i < need[index].length; i++){
if(request[i] > need[index][i]){
judge = true;
}
}
//2.去判断该请求通过1要求了没,在去进行资源校验2,通过就改变值.
if(judge == true){
System.out.println("该请求无法通过该进程的需求(need)检验");
return false;
}else{
//通过了
int i;
for(i = 0; i < available.length; i++){
if(request[i] > available[i]){
break;
}
}
//看第二轮有谁通过了.
//通过了
if(i >= available.length){
//1.去修改需求数组中该请求的值.
for(int z = 0; z < need[index].length; z++){
temporary[0][z] = need[index][z]; //第0行存需求
need[index][z] -= request[z];
}
//2.再去修改可分配资源数的值.和占有数也得改变
for(int z = 0; z < available.length; z++){
temporary[1][z] = available[z]; //第二行去存可分配的
available[z] -= request[z];
}
//修改该进程占有量
for(int z = 0; z < possess[index].length; z++){
temporary[2][z] = possess[index][z]; //第三行存占有量
possess[index][z] += request[z];
}
//3.进行安全性检验.
//为true就成了返回true并输出安全序列
judgement = true; //这是银行家进行的安全性检验.
if(SafetyInspection()) {
System.out.println("该请求成功!!!!");
return true;
}else{
//把所有值修改回去
for(int b = 0; b < possess[index].length; b++){
need[index][b] = temporary[0][b];
available[b] = temporary[1][b];
possess[index][b] = temporary[2][b];
}
System.out.println("该请求通过了,但是无安全序列");
return false;
}
}else{
System.out.println("该请求无法通过可利用资源数(available)的需求检验");
return false;
}
}
}
public void print(){
//System.out.println(" " + " Allocation " + " Need " + " Available " + " finish ")
System.out.println(" " + " Allocation " + " Need " + " Work+Allocation " + " availbale " + " finish ");
for(int i = 0; i < count1; i++){
System.out.print(securitySequence[i]);
System.out.print(" | ");
System.out.print(" ");
for(int j = 0; j < possess[i].length; j++){
System.out.print(" "+possess[securitySequence[i]][j]);
}
System.out.print(" | ");
for(int k = 0; k < need[i].length; k++){
System.out.print(" "+need[securitySequence[i]][k]);
}
System.out.print(" | ");
for(int z = 0; z < availableTrue[i].length; z++){
System.out.print(" "+availableTrue[securitySequence[i]][z]);
}
if (!min) {
System.out.print(" | ");
for (int z = 0; z < available.length; z++) {
System.out.print(" " + (available[z] - (possess[securitySequence[i]][z])));
}
min = true;
}
System.out.print(" | ");
System.out.print(finish[securitySequence[i]]);
System.out.println();
}
}
public void print1(){
//System.out.println(" " + " Allocation " + " Need " + " Available " + " finish ")
System.out.println(" " + " Allocation " + " Need " + " Work+Allocation " + " availbale " + " finish ");
for(int i = 0; i < need.length; i++){
System.out.print(i);
System.out.print(" |");
System.out.print(" ");
for(int j = 0; j < possess[i].length; j++){
System.out.print(" "+possess[i][j]);
}
System.out.print(" | ");
for(int k = 0; k < need[i].length; k++){
System.out.print(" "+need[i][k]);
}
System.out.print(" | ");
for(int z = 0; z < availableTrue[i].length; z++){
System.out.print(" "+availableTrue[i][z]);
}
if (!min) {
System.out.print(" | ");
for (int z = 0; z < available.length; z++) {
System.out.print(" " + available[z]);
}
min = true;
}
System.out.print(" | ");
System.out.print(finish[i]);
System.out.println();
}
}
public void menu(){
System.out.println("欢迎来到银行家算法");
System.out.println("***********************");
System.out.println("*****1.初始化**********");
System.out.println("*****2.安全性检验********");
System.out.println("*****3.银行家算法*********");
System.out.println("*****4.输出**********");
System.out.println("*****5.exit************");
System.out.println("***********************");
}
public void perform() {
Scanner scanner = new Scanner(System.in);
int choice = 0;
while (true) {
menu();
System.out.println("请输入你的选择");
choice = scanner.nextInt();
if (choice == 1) {
Init();
} else if(choice == 2) {
SafetyInspection();
} else if(choice == 3){
ResourceRequest();
} else if (choice == 4) {
print1();
}else if(choice == 5){
break;
}else{
System.out.println("你的输入有误,请重输");
continue;
}
}
}
public static void main(String[] args) {
BankOperation use = new BankOperation();
use.perform();
}
}```