銀行家算法(Banker’s Algorithm)是一個避免死鎖(Deadlock)的著名算法.
1.算法原理
操作系統是銀行家,操作系統管理的資源相當於銀行家管理的資金,進程向操作系統請求分配資源相當於用戶向銀行家貸款。
爲保證資金的安全,銀行家規定:
(1) 當一個顧客對資金的最大需求量不超過銀行家現有的資金時就可接納該顧客;(即request <= available)
(2) 顧客可以分期貸款,但貸款的總數不能超過最大需求量;(即request<=need)
(3) 當銀行家現有的資金不能滿足顧客尚需的貸款數額時,對顧客的貸款可推遲支付,但總能使顧客在有限的時間裏得到貸款;
(4) 當顧客得到所需的全部資金後,一定能在有限的時間裏歸還所有的資金.
2.所用到的數據結構
最大需求max數組:max[i][j] 系統中i個進程中的每一個進程對 j 資源的最大需求.
需求need數組:need[i][j] = max[i][j] - allocation[i[[j] .
已分配allocation數組:allocation[i][j] 系統中每一類資源當前已分配給每一進程的資源數.
可利用資源available數組:是個含有m個元素的數組,其中的每一個元素代表一類可利用的資源數目.
安全序列safeList數組:所有線程均執行完畢,會產生一個執行序列,用該數組來存放.
系統資源source數組:存放系統資源的類型.
3.代碼實現如下
package OS;
import java.util.Arrays;
import java.util.Scanner;
/**
* Created with IntelliJ IDEA.
* Description: 銀行家算法
* User: ZHANFEI
* Date: 19-12-22
* Time: 下午1:15
*/
public class Banker {
//每個進程的最大資源
private int[][] max;
//每個進程需要的資源
private int[][] need;
//每個進程目前有的資源
private int[][] allocation;
//可獲得的資源
private int[] available;
//進程數
private int processNum;
//安全性序列
private int[] safeList;
//資源種類
public static String[] source = new String[]{"A","B","C","D","E"};
public static int sourceNum;
//構造函數
public Banker() {
init();
}
/**
* 手動初始化
*/
public void init() {
Scanner in = new Scanner(System.in);
System.out.println("輸入進程數:");
processNum = in.nextInt();
System.out.println("輸入資源數量:");
sourceNum = in.nextInt();
//對數組初始化
System.out.println("輸入max:");
max = new int[processNum][sourceNum];
for (int i = 0; i < processNum; i++) {
for (int j = 0; j < sourceNum; j++) {
max[i][j] = in.nextInt();
}
}
System.out.println("輸入allocation:");
allocation = new int[processNum][sourceNum];
for (int i = 0; i < processNum; i++) {
for (int j = 0; j < sourceNum; j++) {
allocation[i][j] = in.nextInt();
}
}
need = new int[processNum][sourceNum];
for (int i = 0; i < processNum; i++) {
for (int j = 0; j < sourceNum; j++) {
need[i][j] = max[i][j] - allocation[i][j];
}
}
System.out.println("輸入available:");
available = new int[sourceNum];
for (int i = 0; i < sourceNum; i++) {
available[i] = in.nextInt();
}
}
/**
* 打印每個進程的相關信息
*/
public void print() {
System.out.println("id MAX Need Allocation ");
System.out.print(" ");
for(int j=0;j<3;j++) {
for (int i = 0; i < sourceNum; i++) {
System.out.print(source[i] + " ");
}
}
System.out.println();
for (int i = 0; i < processNum; i++) {
System.out.print(i + " ");
//打印i號進程最大資源數
for(int j=0;j<max[j].length;j++) {
System.out.print(max[i][j] + " ");
}
//打印i號進程需要進程數
for(int j=0;j<need[j].length;j++) {
System.out.print(need[i][j] + " ");
}
//打印i號進程目前獲得進程數
for(int j=0;j<allocation[j].length;j++) {
System.out.print(allocation[i][j] + " ");
}
System.out.println();
}
System.out.println(Arrays.toString(available));
}
/**
* 進行試分配
* @param requestId 試分配的進程id
* @param inRequest 請求的資源數組
* @return
*/
public boolean change(int requestId,int[] inRequest) {
int[] request = inRequest;
//1.判斷request和need的大小
for (int i = 0; i < request.length; i++) {
if(!(request[i] <= need[requestId][i])) {
System.out.println("請求的資源超過了所需要的最大值,請求失敗");
return false;
}
}
//2.判斷request和available的大小
for (int i = 0; i < request.length; i++) {
if( !(request[i] <= available[i])) {
System.out.println("資源不足,請求失敗");
return false;
}
}
//3.進行試分配
//need = need - request ;
//allocation = allocation + request;
//available = available - request;
for(int i=0;i<request.length;i++) {
need[requestId][i] = need[requestId][i] - request[i];
allocation[requestId][i] = allocation[requestId][i] + request[i];
available[i] = available[i] - request[i];
}
//進行安全性檢查
boolean flag = checkSafe(available);
if(flag == true) {
System.out.println("分配成功");
for(int i=0;i<3;i++) {
need[requestId][i] = need[requestId][i] + request[i];
allocation[requestId][i] = allocation[requestId][i] - request[i];
available[i] = available[i] + request[i];
}
return true;
} else {
//不能分配,需要將數據恢復到分配之前
System.out.println("分配失敗");
for(int i=0;i<3;i++) {
need[requestId][i] = need[requestId][i] + request[i];
allocation[requestId][i] = allocation[requestId][i] - request[i];
available[i] = available[i] + request[i];
}
return false;
}
}
/**
* 安全性檢查
* @param available 可獲取資源數組
* @return
*/
public boolean checkSafe(int[] available) {
int[] work = new int[available.length];
for (int i = 0; i < work.length; i++) {
work[i] = available[i];
}
int i=0,n=0;
int j;
boolean[] finish = new boolean[processNum];
safeList = new int[processNum];
while(i<processNum) {
if(finish[i] == false && judge(i,need,work)) {
System.out.println("進程"+i+"分配成功");
//加入到序列中
safeList[n++] = i;
for(int m=0;m<work.length;m++) {
work[m] = work[m] + allocation[i][m];
}
finish[i] = true;
//分配成功 從頭重新開始
i = 0;
} else {
i++;
}
}
for(i = 0;i<finish.length;i++) {
if(finish[i] == false) {
// System.out.println(i+"失敗");
System.out.println(Arrays.toString(safeList));
return false;
}
}
System.out.println(Arrays.toString(safeList));
return true;
}
/**
* 安全性檢測時比較當前進程的 need 和 work
* @param id 當前進程id
* @param need 當前進程所需資源 數組
* @param work 當前系統可提供資源 數組
*/
private boolean judge(int id, int[][] need, int[] work) {
int j;
for (j = 0; j < work.length; j++) {
if(!(need[id][j] <= work[j])){
return false;
}
}
return true;
}
public static void main(String[] args) {
Banker banker = new Banker();
int requestId;
int[] request = new int[sourceNum];
Scanner in = new Scanner(System.in);
banker.print();
while(true) {
System.out.println("輸入需要請求的進程號id():");
requestId = in.nextInt();
System.out.println("輸入需請求的各類資源數目:");
for(int i=0;i<sourceNum;i++) {
System.out.println("請求"+source[i]+"資源的數目:");
request[i] = in.nextInt();
}
//進行安全檢查
banker.change(requestId,request);
System.out.println("是否繼續分配 0/1");
int choice = in.nextInt();
if(choice == 1) {
break;
}
}
}
}
運行結果:
當線程0請求{0,0,0,0} 就相當於檢測T0時刻是否安全.