用Java实现银行家算法
一、银行家算法
银行家算法是这样一种资源分配算法:系统给进程分配资源时,先检查状态是否安全,方法是看它是否有足够的剩余资源满足一个距最大需求最近的进程。
如果有,那么分配资源给该进程,然后接着检查下一个距最大需求最近的进程,如此反复下去。如果所有进程都能获得所需资源,那么该状态是安全的,最初的进程申请资源可以分配。
二、算法所需的数据结构
- Available 表示当前系统可以使用的资源数,使用一维数组来存储
- Request 表示进程向系统申请的各类资源数。使用一维数组实现
- Max 表示当前进程最大需求的资源,使用Java的HashMap存储
- Allocatio 表示当前进程占有的资源数,使用Java的HashMap存储
- Need 表示当前资源还需的资源数,使用Java的HashMap存储
三、银行家算法的算法步骤
当进程向系统申请资源的时候,系统会按照下列步骤进行检查:
- 如果Requst <= Need,进入第二步。否则说明进程的对资源的申请量大于它的最大值,返回False。
- 如果 Request <= Available,进入第三步。否则说明系统没有足够的资源可以分配,进程需等待。返回False。
- 系统尝试将资源分配给进程:
Available = Available - Request;
Allocation = Allocation + Request;
Need = Need - Request;、 - 系统执行安全性检查算法,检查此次资源分配后,系统是否处于安全状态。若安全,才正式将资源分配给进程已完成此次分配;若不安全,试探性分配作废,恢复资源分配情况。让进程等待。
安全性检查算法描述:
定义两个结构 Free(表示系统可用资源数),Finish(表示进程某次检查是否满足)
(1) 初始化 Free = Available,Finish所有进程为False
(2)从进程集合中找出一个能满足下述条件的进程
1.进程在Finish中对应的值是false(表示资源未分配给进程)
2.进程 Need <= Free (表示资源能够分配给进程)
(3)当进程获得资源后,认为进程完成任务,释放资源。
Free = Free + Allocation
Finish= true
跳转到步骤(2)继续执行
经过遍历一个轮回后,若可以达到,Finish中所有进程都是true。则表示系统处于安全状态,否则系统处于不安全状态。
四、银行家算法的代码实现
根据上面的算法步骤我们可以Java来实现算法步骤。
package test.tt;
import Untils.ArrayOperation;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.zip.DataFormatException;
/**
* @author Hognhu
* @Dataon 2020/10/17
* 银行家算法
*
*
*/
public class BlankerAlgorithm {
public Boolean RunBlankerAlgorithm( String PID,
int[] Request,
int[] Available,
HashMap<String ,int []> Max,
HashMap<String ,int []> Allocation,
HashMap<String ,int []> Need) throws DataFormatException {
//第一步 判断是不是超过自己的最大值
if(ArrayOperation.ComparaArray(Request,Max.get(PID)))
return false;
//第二步判断系统有没有符合请求的数据
if(!ArrayOperation.ComparaArray(Available,Request))
return false;
//第三步尝试分配
Available = ArrayOperation.subtraction(Available,Request);
Allocation.replace(PID,ArrayOperation.addition(Allocation.get(PID),Request));
Need.replace(PID,ArrayOperation.subtraction(Need.get(PID),Request));
//构建Finished
String[] keys = getKeys(Max);
HashMap<String ,Boolean> Finished = CreateFalse(keys);
//检查是否安全
if(!SecurityCheck(Finished,Available,Allocation,Need)){
//如果不安全,归还资源
return false;
}
return true;
}
//内循环
private Boolean SecurityCheck(HashMap<String ,Boolean> FalseMap,
int[] Available,
HashMap<String ,int []> Allocation,
HashMap<String ,int []> Need){
//判断size 是否为 0
if(Need.size() == 0)
return true;
Iterator<Map.Entry<String ,int []>> it = Need.entrySet().iterator();
int[] Free = Available;
while(it.hasNext()){
String PID = it.next().getKey();
int[] needProcess = Need.get(PID);
if(!FalseMap.get(PID) && ArrayOperation.ComparaArray(Free,needProcess)) {
//设置标志
FalseMap.replace(PID,false);
//释放资源
Free =ArrayOperation.addition(Free,Allocation.get(PID));
//释放资源
it.remove();
Allocation.remove(PID);
System.out.println("PID="+PID);
//使用递归来遍历各个进程
Boolean result = SecurityCheck(FalseMap,Free,Allocation,Need);
if(result)
return true;
}
}
return false;
}
//创建Finish
private HashMap<String ,Boolean> CreateFalse(String[] keys){
HashMap<String ,Boolean> result = new HashMap<String,Boolean>();
for(String item:keys){
result.put(item,false);
}
return result;
}
//获取所有进程
private String[] getKeys(Map map){
Set<String> set1 = map.keySet();
int size = map.size();
String[] result = new String[size];
int i = 0;
for(String key:set1){
//System.out.println(key);
result[i] = key;
i++;
}
return result;
}
public static void main(String[] args) throws DataFormatException {
//测试银行家算法
BlankerAlgorithm b = new BlankerAlgorithm();
int[] Available = {3,3,2};
//int[] Available = {2,3,0};
int[] request = {1,0,2};
//int[] request = {0,2,0};
//int[] request = {3,3,0};
HashMap<String,int []> Max = new HashMap();
int [] p0 = {7,5,3};
int [] p1 = {3,2,2};
int [] p2 = {9,0,2};
int [] p3 = {2,2,2};
int [] p4 = {4,3,3};
Max.put("p0",p0);
Max.put("p1",p1);
Max.put("p2",p2);
Max.put("p3",p3);
Max.put("p4",p4);
HashMap<String,int []> Allocation = new HashMap();
int [] p00 = {0,1,0};
int [] p11 = {2,0,0};
//int [] p11 = {3,0,2};
int [] p22 = {3,0,2};
int [] p33 = {2,1,1};
int [] p44 = {0,0,2};
Allocation.put("p0",p00);
Allocation.put("p1",p11);
Allocation.put("p2",p22);
Allocation.put("p3",p33);
Allocation.put("p4",p44);
HashMap<String,int []> Need = new HashMap();
int [] p000 = {7,4,3};
int [] p111 = {1,2,2};
int [] p222 = {6,0,0};
int [] p333 = {0,1,1};
int [] p444 = {4,3,1};
Need.put("p0",p000);
Need.put("p1",p111);
Need.put("p2",p222);
Need.put("p3",p333);
Need.put("p4",p444);
System.out.println("安全序列为:");
System.out.println(b.RunBlankerAlgorithm("p1",request,Available,Max,Allocation,Need));
}
}
所使用的工具类ArrayOperation
package Untils;
import org.apache.log4j.Logger;
/**
* @author Hognhu
* @Dataon 2020/10/17
*/
public class ArrayOperation {
static Logger log = Logger.getLogger(ArrayOperation.class);
/**
* 返回 arr1 + arr2
*/
public static int[] addition(int[] arr1, int[] arr2) {
int size = arr1.length;
if (size != arr2.length) throw new NumberFormatException("数组长度不一致!");
//初始化
int[] result = new int[size];
for (int i = 0; i < size; i++) {
result[i] = arr1[i] + arr2[i];
}
return result;
}
/**
* 返回 arr1 - arr2
*/
public static int[] subtraction(int[] arr1, int[] arr2) {
int size = arr1.length;
if (size != arr2.length) throw new NumberFormatException("数组长度不一致!");
//初始化
int[] result = new int[size];
for (int i = 0; i < size; i++) {
result[i] = arr1[i] - arr2[i];
}
return result;
}
/**
* 两个数组大小
**/
public static Boolean ComparaArray(int[] arr1, int[] arr2) {
Boolean result = true;
int size = arr1.length;
if (size != arr2.length) throw new NumberFormatException("数组长度不一致!");
for (int i = 0; i < size; i++) {
if (arr1[i] - arr2[i] < 0)
result = false;
}
return result;
}
//数组数值取半
public static int[] arrayHalve(int[] arr1) {
int[] result = arr1.clone();
int size = arr1.length;
for (int i = 0; i < size; i++) {
result[i] = result[i] / 2;
}
return result;
}
//返回字符串
public static String ArrayToString(int[] arr){
if(arr == null){
log.error("arr 为 null");
return null;
}
StringBuilder s = new StringBuilder();
for(int i = 0;i<3;i++){
s.append(arr[i]+" ");
}
return s.toString();
}
}
需要注意的点是:
第一:市面上大多数表示MAX、Allocation、Need等都是使用二维数组,我这里因为需要记住进程名字所以我就使用Java的HashMap来表示这些数据结构。个人感觉HashMap来计算会舒服很多。
第二:在系统安全性检查的时候,需要我们去遍历一个个满足条件的进程。我感觉用递归会很方便去解决这个问题,用循环的话太麻烦了/(ㄒoㄒ)/~~。
总体就这样,有什么问题可以评论区留言,或者更好的看法。可以在评论区跟我探讨探讨。