银行家算法(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时刻是否安全.