銀行家算法,能戳到這裏面的話,想必大家都有了解。
銀行家算法的基本思想是:分配資源之前,判斷系統是否是安全的;若是,才分配。它是最具有代表性的避免死鎖的算法。設進程 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的大小,讓你看到找不到下一個進程。