银行家算法,能戳到这里面的话,想必大家都有了解。
银行家算法的基本思想是:分配资源之前,判断系统是否是安全的;若是,才分配。它是最具有代表性的避免死锁的算法。设进程 process 提出请求request[i],则银行家算法按如下规则进行判断:
(1)如果 request[process][i] <= need[process][i],则转(2);否则,出错。
(2)如果 request[process][i] <= available[i],则转(3);否则,等待。
(3)系统试探分配资源,修改相关数据:
available[i]-= request[process][i];
allocation[process][i]+= request[process][i];
need[process][i]-= request[process][i];
(4)系统执行安全性检查,如安全,则分配成立;否则试探险性分配作废,系统恢复原状,
进程等待。
程序流程图:
- 先初始化资源总数资源;
- 再初始化各个进程资源情况
- 查看请求资源是否小于进程所需
- 查看请求资源是否小于系统所有
- 进行安全性检查
1)先试分配,检查状态是否安全,找出安全序列
2)如果找到安全序列,则直接修改
3)找不到安全序列,还原修改值。
注意: 如果请求的资源数刚好等于进程仍然所需要的,给完之后要回收进程的资源数,即把当前进程的资源数加到avaliable里面,不然下一步可能发生死锁!
代码:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
class Process{
String name; //进程名字
int allocation[]; //已分配的资源数
int MaxNeed[]; //最大需求数量
int needs[]; //仍然需要
boolean finshined=false; //状态,这个状态用来指明进程分配过程的状态
@Override
public String toString() {
return "Process{" +
"name='" + name + '\'' +
", allocation=" + Arrays.toString(allocation) +
//", MaxNeed=" + Arrays.toString(MaxNeed) + 可选项,最大需求矩阵不输出
", needs=" + Arrays.toString(needs) +
", finshined=" + finshined +
'}';//重写tostring方法,用来输出进程信息
}
}
public class Bank {
private static int KINDS=0; //资源种类
private static int[] resource; //总资源数
private static int ProcessCount; //进程数量
private static List<Process> team;//进程数组
private static int[] avaliable; //当前可分配资源
public static void InitAllResource(){ //初始化总资源数和进程数量
System.out.println("请输入资源种类数量:");
Scanner sc=new Scanner(System.in);
KINDS=sc.nextInt();
resource=new int[KINDS]; //资源总类数
//各资源数量
for(int i=0;i<resource.length;i++){
System.out.println("请输入第"+i+"种总资源数");
resource[i]=sc.nextInt();
}
}
public static void InitProcess(){//初始化进程
if(KINDS==0){
System.out.println("请初始化总资源数");
return;
}
Scanner scanner=new Scanner(System.in);
System.out.println("请输入进程的个数");
ProcessCount=scanner.nextInt(); //初始化进程个数
team=new ArrayList<>();
for(int i=0;i<ProcessCount;i++){
Process newProcess=new Process();//每次创建一个新的进程信息,并对其初始化
System.out.println("请输入进程的名字:");
newProcess.name=scanner.next();
String name=newProcess.name;
newProcess.MaxNeed=new int[KINDS];
for(int j=0;j<KINDS;j++){
System.out.println("请输入"+name+"进程对"+j+"种资源最大需求数量");
newProcess.MaxNeed[j]=scanner.nextInt();
}
newProcess.allocation=new int[KINDS];
for(int j=0;j<KINDS;j++){
System.out.println("请输入"+name+"进程对"+j+"种资源已分配数量");
newProcess.allocation[j]=scanner.nextInt();
}
team.add(newProcess);//插入顺序表
}
for(int i=0;i<team.size();i++){
team.get(i).needs=new int[KINDS];
for(int j=0;j<KINDS;j++){
team.get(i).needs[j]=team.get(i).MaxNeed[j]-team.get(i).allocation[j];
}
}//根据输入的已分配和最大需求,初始化各个进程的仍需
}
public static void setAvaliable(){
avaliable=new int[KINDS];
for(int i=0;i<KINDS;i++){
for(int j=0;j<team.size();j++) {
avaliable[i] +=team.get(j).allocation[i];
}
}
for (int i=0;i<avaliable.length;i++){
avaliable[i]=resource[i]-avaliable[i];
}
}
public static boolean SafeCheck(){
if(team == null){
System.out.println("请初始化进程资源信息!");
return false;
}
for(int i=0;i<KINDS;i++){//初始化乱输出
if(avaliable[i]<0){
System.out.println("当前状态错误!请重新初始化!");
System.out.println(Arrays.toString(avaliable));
team=null;
return false;
}
}
String[] safeteam=new String[ProcessCount];//存放安全序列
int safecount=0;//记录安全序列的序数
int work[]=new int[KINDS];
for(int i=0;i<KINDS;i++){
work[i]=avaliable[i]; //把当前的avaliable数组的值放置到work进行试分配
}
int index=0;//循环找进程顺序表的下标
boolean choose=false;//选择器,看当前状态是否能分配
int tmp=0;//计算值是否达到了进程长度,即说明查询一圈。
while (safecount < team.size() && tmp <team.size()){
//当安全序列有效数小于进程数 或者 查询小于一圈
if(index >=team.size()){
index=0; //防止越界,循环查找
}
if(!team.get(index).finshined){//判断当前状态
for(int i=0;i<KINDS;i++){//循环比较可用和进程所需,满足置选择器为true
if(team.get(index).needs[i]>work[i]){
choose=false;
tmp++;
index++;
break;
}else {
choose=true;
}
}
if(choose){ //找到能分配的,修改work数组,暂时修改状态值
for (int j=0;j<KINDS;j++){
work[j]=work[j]+team.get(index).allocation[j];
}
team.get(index).finshined=true;
safeteam[safecount]=team.get(index).name;
safecount++;
index++;
tmp=0;//重新计数
}
}else {
tmp++;//当前进程已查找,增加查找次数
index++;//增加下标值
}
}
for(int i=0;i<safeteam.length;i++){
if(safeteam[i] == null){//安全队列有一个为空的话,说明不安全,输出阻塞进程信息
System.out.println("当前状态不安全");
Printmatrix(work);
for(int k=0;k<team.size();k++){
team.get(k).finshined=false;//把进程状态全部还原
}
return false;
}
}
System.out.println("当前状态安全,安全序列为:");
PrinSafe(safeteam);
boolean chice=false;
for(int i=0;i<KINDS;i++){
if(team.get(index).needs[i] !=0){
chice=false;
break;
}else {
chice=true;
}
}
if(chice){
for(int l=0;l<KINDS;l++){
avaliable[l]=team.get(index).allocation[l];
team.get(index).allocation[l]=0;
}
}
for(int k=0;k<team.size();k++){
team.get(k).finshined=false;//把进程状态全部还原
}
return true;
}
private static void PrinSafe(String[] Safe){
//输出安全序列
for(int i=0;i<Safe.length;i++){
if(i==0){
System.out.print("[");
}
if(i!=Safe.length-1) {
System.out.print(Safe[i] + "、");
}else {
System.out.print(Safe[i]+"]");
}
}
System.out.println();
int[] work=new int[KINDS];
for(int i=0;i<Safe.length;i++){
for(int j=0;j<team.size();j++){
if(Safe[i].equals(team.get(j).name)){
if(i==0){//第一个的话就是把avaliable+第一个进程的allocation
System.out.println("当前可用资源数:"+Arrays.toString(avaliable));
for(int k=0;k<KINDS;k++){
work[k]=team.get(j).allocation[k]+avaliable[k];
}
System.out.println(team.get(j));//初始化work的初值
System.out.println("当前可用资源数为"+Arrays.toString(work));
break;
}else{
System.out.println(team.get(j));
for(int k=0;k<KINDS;k++){
work[k]=team.get(j).allocation[k]+work[k];
}
System.out.println("当前可用资源数为"+Arrays.toString(work));
break;
}
}
}
}
System.out.println();
}
public static void Printmatrix(){
//无参数的时候,就是显示当前的进程信息;
if(team == null){
System.out.println("请初始化进程资源信息!");
return ;
}
System.out.println("资源总数"+Arrays.toString(resource));
System.out.println("当前可用资源数"+Arrays.toString(avaliable));
for(int i=0;i<team.size();i++){
System.out.println(team.get(i));
}
}
public static void Printmatrix(int[] work){
//有参数的时候,就是显示当前可用的资源数,和各个进程运行的情况4
if(team == null){
System.out.println("请初始化进程资源信息!");
return ;
}
System.out.println("资源总数"+Arrays.toString(work));
System.out.println("当前可用资源数"+Arrays.toString(avaliable));
for(int i=0;i<team.size();i++){
System.out.println(team.get(i));
}
}
public static void Blank(){
if(team == null){
System.out.println("请初始化进程资源信息!");
return ;
}
Scanner scanner=new Scanner(System.in);
System.out.println("请输入你要分配进程名字");
String name=scanner.next();
for(int i=0;i<team.size();i++){
if(team.get(i).name.equals(name)){
int request[]=new int[KINDS];
for(int j=0;j<KINDS;j++){
System.out.println("请输入要分配的第"+j+"种资源数");
request[j]=scanner.nextInt();//保存request的值
}
for(int j=0;j<KINDS;j++){
//是否大于可利用数
if(team.get(i).needs[j]<request[j]){
System.out.println("错误!请求数量大于进程所需");
return;
}
}
for(int j=0;j<KINDS;j++){
//是否大于当前可用的资源数
if(avaliable[j]<request[j]){
System.out.println("错误!请求数量大于可以分配资源");
return;
}
}//前两种都通过
TryAllcotion(i,request);//i为进程的ID,request为请求资源数
return;
}
}
System.out.println("请核对后进程名进行检查");
}
private static void TryAllcotion(int i,int[] request){
for(int j=0;j<KINDS;j++){
//把这个暂时分配给i进程,修改其need和allocation,修改当前状态可用资源数
team.get(i).allocation[j]+=request[j];
team.get(i).needs[j]-=request[j];
avaliable[j]-=request[j];
}
if(!SafeCheck()){//安全性检查,不安全的话,还原刚才分配所得
System.out.println("状态不安全,未分配");
for(int j=0;j<KINDS;j++){
team.get(i).allocation[j]-=request[j];
team.get(i).needs[j]+=request[j];
avaliable[j]+=request[j];
}
return;
}
System.out.println("状态安全,已分配");
}
public static void menu(){
Scanner sc=new Scanner(System.in);
int choice=1;
while(choice != 0){
System.out.println("********************************");
System.out.println("* 1.初始化资源总数 *");
System.out.println("* 2.进程资源数量 *");
System.out.println("* 3.安全性检测 *");
System.out.println("* 4.银行家算法 *");
System.out.println("* 5.显示进程状态 *");
System.out.println("* 0.退出 *");
System.out.println("********************************");
System.out.println("请输入你的选项");
choice=sc.nextInt();
if(choice == 0){
return;
}else if(choice == 1){
InitAllResource();//初始化资源总数量和各个资源最大数量
}else if(choice == 2){
InitProcess();//初始化各个进程
setAvaliable();//初始化可分配资源数
}else if(choice ==3){
SafeCheck();
} else if(choice == 4){
Blank();
}else if(choice == 5){
Printmatrix();
}else {
System.out.println("输入错误,请检查后重新输入");
}
}
}
public static void main(String[] args) {
menu();
}
}
代码很简单,我注释也写的比较详细。对了,每次检查过程中显示的列表信息,仅仅只是试着去分配的过程信息,如果要看当前真正的信息的话,请在菜单里面选择5。
代码会显示阻塞到哪一步。比如说:P0,P1,P2,P3,P4进程,找到了[P1,P4],然后work的值找不到其余的进程后,就会被阻塞,代码就会显示P1,P2的状态为True,其余的进程都是false,并且会显示work的大小,让你看到找不到下一个进程。
来源:CSDN
作者:阴阳两界
链接:https://blog.csdn.net/qq_45349785/article/details/103713342