銀行家算法(詳解加代碼)

銀行家算法,能戳到這裏面的話,想必大家都有了解。

銀行家算法的基本思想是:分配資源之前,判斷系統是否是安全的;若是,才分配。它是最具有代表性的避免死鎖的算法。設進程 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. 查看請求資源是否小於進程所需
  4. 查看請求資源是否小於系統所有
  5. 進行安全性檢查
    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的大小,讓你看到找不到下一個進程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章