银行家算法

一. 要求
<1>.有录入界面动态录入进程数,资源种类数,各类资源总数,t0时刻各进程的最大需求数,已分配数等信息.
<2>.有算法选择界面,能够进行安全性检验,对进程动态请求资源的银行家算法检查,退出等的功能选择,要求可以进行多进程多次的资源请求.
<3>.有输出界面,要求能够输出安全性检查的结果,如安全能够输出安全序列,能够输出进程请求资源后是否分配的结果,若不能分配要输出原因,如果能够分配,要输出分配后进程及资源的状态.

二 …初始化
这个银行家算法我的思想就是用数组去写,不用太麻烦,直接数组整起再去填值就OK了,
<1>.先去初始化资源总数和进程总数.
<2>.有了这2个数,不是所有的二维数组和一维数组的长度就定了.
<3>.后来去给 maxNeed[][](t0时刻最大资源总数),possess[][](已分配资源数),还有
resources[](各类资源总数)这些数组赋值,去计算available[](可利用资源),need[][](进程所需要资源数).这样基本上就OK了
<4>我还定义了一个availableTrue[][]这个二维数组,就是在利用available[]这个一维数组每次计算把available + possess的值赋给availableTrue[][],来保存.其实availableTrue[][]是书上的work + Allocation
<5>.还有finish[](当前状态),securitySequence[](安全队列)一并初始化,其余的4个数据成员变量是我的动态输入必需品,随意的.

三 . 安全性检验

如果存在一个由系统中所有进程构成的安全序列P1,…,Pn,则系统处于安全状态。安全状态一定是没有死锁发生。

我的思想先设置一个判断器和计数器.
计数器:先来个变量来记下遍历一次need[][]数组之前的计数器值,遍历一遍后,
<1>.如果计数器值与之前记录变量相等并且计数器值小于进程总数,那就是卡住了,就不安全直接返回,输出不安全队列.
<2>.如果不等于并且计数器值小于进程总数就继续.如果不等于并且等于进程总数,就安全了输出安全队列.
判断器:在第二个for循环去遍历该进程资源数是否小于可利用资源数,小于就判断通过直接去回收,不小于就直接下一个进程.
就是去遍历need二维数组运用这俩个就可以简单的输出安全和不安全,之后再安全和不安全返回之前得把available[],finish[]和securitySequence[]数组置为初始值.就可以连续检验并在银行家算法中调用.
这个方法为boolean类型是为了银行家算法中调用,在过程中记录第一个进入安全序列的进程下标是为了返回available的初值,在这个方法中其他变量基本上都是为了动态输入.

四. 银行家算法

银行家算法(Banker’s Algorithm)是一个避免死锁(Deadlock)的著名算法,是由艾兹格·迪杰斯特拉在1965年为T.H.E系统设计的一种避免死锁产生的算法。它以银行借贷系统的分配策略为基础,判断并保证系统的安全运行。

我的思想是开始不得先输入你要请求的进程是哪个,然后初始化请求数组去存入你输得各个资源数.然后就可以分为3步了.
<1>.去判断他请求的资源是否小于他这个进程的need资源,小于就可以进行第二步,大于就返回该请求无法通过该进程的需求(need)检验.
<2>.再去判断他请求资源是否小于现有的可利用资源available,小于就进行第三步,大于就返回该请求无法通过可利用资源数(available)的需求检验.
<3>.在第二步之后就得去修改这个进程的need资源数和possess已分配资源数,还有现有分配资源数available,同时还得保存这3个修改值之前的值.这时候又得2步(安全或不安全):
(1).安全:直接按修改的值去调用安全性检验算法.同时在这里要注意一个问题就是请求过后他的need被修改为0 0 0 了 ,这时候就应该进程回收把他的possess 也置为 0 0 0,这就是在安全性检验中回收里面的那个if里的代码.
(2)不安全:就得把之前保存的修改之前的值全赋回去.就完了.

五. 动态输出(可有可无)
这个print()是实现动态输出的,纯属弄这好看,就是用count1记录当前回收了几个进程,就直接输出几个.用了进程睡眠(Thread.sleep())让主进程等待1.5秒.

六. 一些感悟
<1>. 数组写这个还是太生硬了,不太灵活想实现一些东西就得定义全局变量才能实现,我觉得用对象去写应该要灵活好多.
<2>.写代码之前注释很重要,写了注释就直接往里填代码就OK了.
<3>.界面很重要,我这个界面太low了.

七. 具体代码
注释很多,不加讲解了.

import java.util.Arrays;
import java.util.Scanner;

public class BankOperation {

    public int resourceType; //资源种类
    public int process; //进程个数
    public int[][] maxNeed;    //t0时刻各进程的最大需求数
    public int[][] possess; //每个进程的资源已分配数
    public int[][] need; //每个进程的资源需要数
    public int[] resources; //各类资源总数
    public int[] available; //可利用资源数
    public boolean[] finish; //判断进程是否可被安全
    public int[] securitySequence; //安全序列
    public int[][] availableTrue; //实际的可利用资源数.
    public int count1 = 0; //去记录他几个进程进来了.
    public boolean judgement = false; //这是判断到底是银行家算法还是安全性检验进行的检验.
    public int index = 0; //银行家算法请求的进程
    public boolean min = false; //动态输出的必需品


    public void Init(){  //初始化
        Scanner scanner = new Scanner(System.in);
        //资源初始化
        System.out.println("请你输入你的资源种类");
        resourceType = scanner.nextInt();
        //去具体初始化各类资源数
        resources = new int[resourceType];
        System.out.println("请你输入这" +resourceType+ "类资源的具体值");
        for(int i = 0; i < resourceType; i++){
            System.out.println("请你输入第" +i+ "类资源总数");
            resources[i] = scanner.nextInt();
        }

        //进程初始化
        System.out.println("请你输入你的进程总数");
        process = scanner.nextInt();

        //可以去初始化各个二维数组的空间大小了
        maxNeed = new int[process][resourceType];
        possess = new int[process][resourceType];
        need = new int[process][resourceType];
        availableTrue = new int[process][resourceType];

        //给t0时刻个进程需求数赋值
        System.out.println("请你给t0时刻各进程去赋资源数");
        assignment(maxNeed);

        //给各个进程已分配数组赋值
        System.out.println("请你给各进程已分配资源数赋值");
        assignment(possess);

        //去求个进程的需求数组

        for(int i = 0; i < need.length; i++){
            for(int j = 0; j < need[i].length; j++){
                need[i][j] = maxNeed[i][j] - possess[i][j];
            }
        }

        //去初始化一下可利用资源数,去遍历已分配数组,用总数一减就OK了.
        int row = possess.length;
        int col = possess[0].length;
        available = new int[resourceType];
        for(int i = 0; i < col; i++){
            int sum = 0; //记录那一列之和
            for(int j = 0; j < row; j++){
                sum += possess[j][i];
            }
            available[i] = resources[i] - sum;
            availableTrue[0][i] = available[i]; //给实际的可利用数组赋值.
        }

        //去初始化一下boolean数组,初值为false不用管
        finish = new boolean[process];

        //去初始化一下安全序列,全为666预防0那个.

        securitySequence = new int[process];
        for(int i = 0; i < securitySequence.length; i++){
            securitySequence[i] = 666;
        }
    }

    public void assignment(int[][] tem){
        Scanner scanner = new Scanner(System.in);
        for(int i = 0; i < tem.length; i++){
            System.out.println("请你给第" +i+ "进程赋值");
            for(int j = 0; j < tem[i].length; j++){
                tem[i][j] = scanner.nextInt();
            }
        }
    }



    public boolean SafetyInspection(){  //安全性检验
        int count = 0; //用来记录进程数.和遍历一遍看有无改变.
        boolean judge = false; //再进程每行判断起作用
        int index1 = 0; //去记录一下第一次安全队列执行的哪一个下标.
        //去遍历需求数组,如果可利用的资源数大于等于某个进程的需求数,就回收.
        // 否则继续遍历,这时候就看count与finish数组了.

        while(true){
            int tem = count;   //记录一下开始进程数.
            for(int i = 0; i < need.length; i++){
                judge = false; //每次都需要布置初始值
                for(int j = 0; j < need[0].length; j++){
                    //去判断
                    if(finish[i] == true || available[j] < need[i][j]){
                        judge = true;
                        break;  //是true就没必要在继续了.因为一个小了,其他无所谓
                    }
                }
                if(judge == false){ //回收
                        for (int z = 0; z < possess[i].length; z++) {
                            available[z] += possess[i][z];
                            availableTrue[i][z] = available[z];  //给实际的可利用数组赋值.
                        }
                    if(index == i && judgement == true) {  //这是need为0的进程 需要被回收.
                        boolean gg = false;
                        for (int v = 0; v < need[i].length; v++) {
                            if (need[i][v] != 0) {
                                gg = true;
                            }
                        }
                        if (gg == false) { //全为0要被回收.
                            for (int v = 0; v < need[i].length; v++) {
                                possess[i][v] = 0;
                            }
                        }
                        judgement = false; //用完置为原值.
                    }
                    finish[i] = true;  //置true
                    securitySequence[count] = i; //更新安全序列
                    count += 1;  //每次循环完有进程被回收就加1.
                    count1 += 1;
                    //来个输出的过2秒输一下.
                    try {
                        Thread.sleep(1500);//括号里面的5000代表5000毫秒,也就是5秒,可以该成你需要的时间
                        print();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    if(count == 1){  //记录第一个进入安全队列的.
                        index1 = i;
                    }
                }
            }

            if(count == process){ //完成完之后,其余值不变,把假的可利用值赋回来.
                System.out.print("该作业安全,你的安全序列为: ");
                System.out.println(Arrays.toString(securitySequence));

                //把假的可分配资源数置为初始值.
                for(int i = 0; i < availableTrue[0].length; i++){
                    available[i] = availableTrue[index1][i] - possess[index1][i];
                }

                //把finish数组置为初始值
                for(int i = 0; i < finish.length; i++){
                    finish[i] = false;
                }

                //安全队列也得重新赋回初值,要不我的不安全队列就不行了.
                for(int i = 0; i < securitySequence.length; i++){
                    securitySequence[i] = 666;
                }
                count1 = 0;  //动态输入每次安全系列弄完就得置为0.
                min = false;
                return true;
            }
            //在一次循环之后,如果count值没有改变,则就没有进程要求被满足,就应该break,不安全.
            if(count == tem && count < process){
                int[] nosafe = new int[process];
                int j;
                int count11 = 0;
                System.out.println("不安全,因为这几个序列中需求不被满足");
                for(int i = 0; i < securitySequence.length; i++){
                    for(j = 0; j < securitySequence.length; j++){
                        if(i == securitySequence[j]){  //安全序列数值肯定是 0 ~ process里这些数,所以直接去遍历安全序列数组,谁没有谁不安全.
                            break;
                        }
                    }
                    if(j >= securitySequence.length){
                        nosafe[count11] = i;  //不安全的全存在nosafe数组中
                    }
                }
                for (int i = 0; i < count11; i++){
                    System.out.print("   " + nosafe[i]);
                }

                //2.把所有值都赋值为原来的部分.
                //把初始值赋回来.
                for(int i = 0; i < availableTrue[0].length; i++){
                    available[i] = availableTrue[index1][i] - possess[index1][i];  //找到第一次进安全序列的进程
                    // ,然后直接求出开始的可分配资源.
                }

                //把finish数组中执行过的数组置为false
                for(int i = 0; i < finish.length; i++){
                    finish[i] = false;
                }
                //安全队列也得重新赋回初值,要不我的不安全队列就不行了.
                for(int i = 0; i < securitySequence.length; i++){
                    securitySequence[i] = 666;
                }
                count1 = 0;  //动态输入每次安全系列弄完就得置为0.
                min = false;
                return false;
            }
        }
    }


    public boolean ResourceRequest(){  //资源性请求
        min = false;
        //如果你的检验通过了,但是没有安全序列,则不能修改这个数组
        int[][] temporary = new int[3][resourceType]; //去存请求的那个最初的需求和最初的占有和最初的可分配资源
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入你要给几号进程请求");
        index = scanner.nextInt();
        int[] request = new int[resourceType];
        System.out.println("请输入你的请求资源数");
        for(int i = 0; i < request.length; i++){
            request[i] = scanner.nextInt();
        }
        //去进行资源校验,继续设置判断器.
        boolean judge = false; //为true就通过.
        //1.和该进程的请求去校验.
        for(int i = 0; i < need[index].length; i++){
            if(request[i] > need[index][i]){
                judge = true;
            }
        }
        //2.去判断该请求通过1要求了没,在去进行资源校验2,通过就改变值.
        if(judge == true){
            System.out.println("该请求无法通过该进程的需求(need)检验");
            return false;
        }else{
            //通过了
            int i;
            for(i = 0; i < available.length; i++){
                if(request[i] > available[i]){
                    break;
                }
            }
            //看第二轮有谁通过了.
            //通过了
            if(i >= available.length){
                //1.去修改需求数组中该请求的值.
                for(int z = 0; z < need[index].length; z++){
                    temporary[0][z] = need[index][z]; //第0行存需求
                    need[index][z] -= request[z];
                }
                //2.再去修改可分配资源数的值.和占有数也得改变
                for(int z = 0; z < available.length; z++){
                    temporary[1][z] = available[z]; //第二行去存可分配的
                    available[z] -= request[z];
                }
                //修改该进程占有量

                for(int z = 0; z < possess[index].length; z++){
                    temporary[2][z] = possess[index][z]; //第三行存占有量
                    possess[index][z] += request[z];
                }
                //3.进行安全性检验.
                //为true就成了返回true并输出安全序列
                judgement = true; //这是银行家进行的安全性检验.
                if(SafetyInspection()) {
                    System.out.println("该请求成功!!!!");
                    return true;
                }else{
                    //把所有值修改回去
                    for(int b = 0; b < possess[index].length; b++){
                        need[index][b] = temporary[0][b];
                        available[b] = temporary[1][b];
                        possess[index][b] = temporary[2][b];
                    }
                    System.out.println("该请求通过了,但是无安全序列");
                    return false;
                }
            }else{
                System.out.println("该请求无法通过可利用资源数(available)的需求检验");
                return false;
            }
        }
    }
    public void print(){
        //System.out.println("      " + "   Allocation     " + "         Need   " + "         Available   "  + "     finish ")
        System.out.println("       " + "    Allocation     " + "  Need   " + "   Work+Allocation   "  + "      availbale    " + "   finish ");
        for(int i = 0; i < count1; i++){
            System.out.print(securitySequence[i]);
            System.out.print("  | ");
            System.out.print("  ");
            for(int j = 0; j < possess[i].length; j++){
                System.out.print("   "+possess[securitySequence[i]][j]);
            }
            System.out.print("  |  ");
            for(int k = 0; k < need[i].length; k++){
                System.out.print("   "+need[securitySequence[i]][k]);
            }
            System.out.print("  | ");
            for(int z = 0; z < availableTrue[i].length; z++){
                System.out.print("   "+availableTrue[securitySequence[i]][z]);
            }
            if (!min) {
                System.out.print(" |  ");
                for (int z = 0; z < available.length; z++) {
                    System.out.print("     " + (available[z] - (possess[securitySequence[i]][z])));
                }
                min = true;
            }
            System.out.print("  |   ");
            System.out.print(finish[securitySequence[i]]);
            System.out.println();
        }
    }
    public void print1(){
        //System.out.println("      " + "   Allocation     " + "         Need   " + "         Available   "  + "     finish ")
        System.out.println("      " + "    Allocation     " + "  Need   " + "   Work+Allocation   "  + "      availbale    " + "   finish ");
        for(int i = 0; i < need.length; i++){
            System.out.print(i);
            System.out.print(" |");
            System.out.print("  ");
            for(int j = 0; j < possess[i].length; j++){
                System.out.print("   "+possess[i][j]);
            }
            System.out.print("  |  ");
            for(int k = 0; k < need[i].length; k++){
                System.out.print("   "+need[i][k]);
            }
            System.out.print("  | ");
            for(int z = 0; z < availableTrue[i].length; z++){
                System.out.print("    "+availableTrue[i][z]);
            }
            if (!min) {
                System.out.print("  |   ");
                for (int z = 0; z < available.length; z++) {
                    System.out.print("     " + available[z]);
                }
                min = true;
            }
            System.out.print("  |   ");
            System.out.print(finish[i]);
            System.out.println();
        }
    }
    public void menu(){
        System.out.println("欢迎来到银行家算法");
        System.out.println("***********************");
        System.out.println("*****1.初始化**********");
        System.out.println("*****2.安全性检验********");
        System.out.println("*****3.银行家算法*********");
        System.out.println("*****4.输出**********");
        System.out.println("*****5.exit************");
        System.out.println("***********************");
    }
    public  void perform() {
        Scanner scanner = new Scanner(System.in);
        int choice = 0;
        while (true) {
            menu();
            System.out.println("请输入你的选择");
            choice = scanner.nextInt();
            if (choice == 1) {
                Init();
            } else if(choice == 2) {
                SafetyInspection();
            } else if(choice == 3){
                ResourceRequest();
            } else if (choice == 4) {
                print1();
            }else if(choice == 5){
                break;
            }else{
                System.out.println("你的输入有误,请重输");
                continue;
            }
        }
    }
    public static void main(String[] args) {
        BankOperation use = new BankOperation();
        use.perform();
    }
}```



      
    



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值