JAVA-银行家算法

简介: JAVA-银行家算法

银行家算法是一个避免死锁的著名算法,是由艾兹格.迪杰斯特拉设计的一种避免死锁产生的算法。它以银行借贷系统的分配策略为基础,判断并保证系统的安全运行。

一、背景介绍

在银行中,客户申请贷款的数量是有限的,每个客户在第一次申请贷款时要声明完成该项目所需的最大资金量,在满足所有贷款要求时,客户应及时归还。银行家在客户申请的贷款数量不超过自己拥有的最大值时,都应尽量满足客户的需要。在这样的描述中,银行家就好比操作系统,资金就是资源,客户就相当于要申请资源的进程。

安全序列:指一个进程序列{p1,......,pn}是安全的,即对于每一个进程pi(1<= i<=n),它以后尚需要的资源量不超过系统当前剩余资源量与所有进程pj(j<i)当前占有资源量之和。


安全状态一定是没有死锁发生的。


不安全状态:不存在一个安全序列,不安全状态一定导致死锁。

二、相关数据结构

银行家算法中的数据结构
  • 设系统中有m种不同资源, n个进程
  • Available向量: 系统中尚未分配的每种资源的总量
  • Available[j]: 尚未分配的资源j的数量
  • Max矩阵: 各个进程对每种资源的最大需求量(进程事先声明)
  • Max[i, j](Claim[i,j]): 进程i 对资源j 的最大需求量
  • Allocation矩阵: 当前资源分配状况
  • Allocation[i, j]: 进程i获得的资源j的数量
  • Need矩阵: 每个进程还需要的资源的数量
  • Need[i, j]: 进程i尚需的资源j的数量
各数据结构之间的关系
  • Resource[j] = Available[j] + (Allocation[1, j] + Allocation[2, j] + … + Allocation[n, j])
  • Max[i, j] <= Resource[j]
  • Allocation[i, j] <= Max[i, j]
  • Allocation[i, j] + Need[i, j] =Max[i, j]
安全性算法

1. 设Work和Finish 分别是长度为m 和n 的向量,按如下方式进行初始化:

    Work = Available

           Finish [i] = false ( i =1,2, …, n)

2. 查找这样的i使其满足:(a) Finish [i] = false  (b) Need i <=Work

3. 如果没有这样的 i 存在,那么就转到第4步.

4. Work = Work + Allocation i Finish[i] = True 返回到第2步.

5. 如果对所有的i,Finish [i] == True ,那么系统处于安全状态

例题讲解1

R1,R2,R3的数量分别为(9,3,6); Available(1,1,2)

问:1.该时刻是否为安全状态

      2.进程A请求资源Request(1,0,1),能够分配吗?为什么?

解题步骤如下:(注:!!!圆圈序号表示做题方法,答案中不必出现。)

1.画出如下表格

①首先将available中的数字填在首行work中

②available(1,1,2)分别和A、B、C、D中的need相比较,倘若小于,则从上往下依次选择。例如B(1,0,2)小于则将B填入第一行,其后need、Allocation依次填入


③接着计算work+allocation的值与R1R2R3(9,3,6)相比较,小于则为true


④将上一行中的work+allocation的值填入下一行work中,接着重复②之后的操作。


⑤直到填完最后一个进程,finish都为true则此时产生了一个安全序列。


2.①将requestA和needA和Available相比较,若小于二者则可继续判断,否则不够分配。


RequestA(1,0,1)<=Need(2,2,2)

RequestA(1,0,1)<=Available(1,1,2)


②修改A的allocation和need,allocation+requestA , need-requestA 并将值填入其中。

假定满足进程A的要求,为它分配所申请的资源,并且修改AllocaitonA 和 NeedA,得到:


此时:Available=(0,1,1):不能分配给任何进程;因此不能分配此次请求。


③此时available-requsetA得到(0,1,1)此时,更新A的状态,重复第一问判断是否存在安全状态。通过比较我们发现available(0,1,1)小于任何一个进程的Need故无法进行分配

例题讲解2

设系统在T0时刻系统状态如下:剩余资源向量为: A=(2, 3, 3)


问:① T0时刻是否为安全状态?若是,请给出安全序列。

      ② 在T0时刻若进程P2请求资源(0,3,4),是否能实施资源分配?为什么?

      ③ 在②的基础上,若进程P4请求资源(2,0,1),是否能实施资源分配?为什么?


解析:与题1不同的是,题2并未给出一个系统的表,因此需要在草稿本上列出表格的大概状态。最大资源需求(Max)已分配资源数量(allocation)剩余资源向量(available)


need = max - allocation,其余步骤参考题1 即可


答案:1. 是,安全序列:p4, p5, p1, p2, p3


           2.因为 R(0,3,4)> A (2,3,3,)所以不能分配。


           3.因为R(2,0,1)<=N4(2, 0,1)且 < A(2,3,3)假设可以满足,则N4=(0, 0, 0), A= (0,3,2),在此基础上,是安全的,因此可以实施分配。安全序列为:p4,p5,p1,p2,p3

三、参考示例代码

import java.util.Arrays;
 
class BankersAlgorithm {
    private int[][] max;   // 最大需求矩阵
    private int[][] allocation;   // 已分配资源矩阵
    private int[][] need;   // 剩余需求矩阵
    private int[] available;   // 可用资源向量
    private int[][] request;   // 请求资源矩阵
 
    public BankersAlgorithm(int[][] max, int[][] allocation, int[] available) {
        this.max = max;
        this.allocation = allocation;
        this.available = available;
 
        int numOfProcesses = max.length;
        int numOfResources = available.length;
 
        this.need = new int[numOfProcesses][numOfResources];
        this.request = new int[numOfProcesses][numOfResources];
 
        // 计算剩余需求矩阵
        for (int i = 0; i < numOfProcesses; i++) {
            for (int j = 0; j < numOfResources; j++) {
                need[i][j] = max[i][j] - allocation[i][j];
            }
        }
    }
 
    public void requestResources(int pid, int[] request) {
        System.out.println("进程 " + pid + " 请求资源: " + Arrays.toString(request));
        boolean safe = checkSafety(pid, request);
 
        if (safe) {
            System.out.println("请求通过,为进程 " + pid + " 分配资源 " + Arrays.toString(request));
            allocateResources(pid, request);
        } else {
            System.out.println("请求被拒绝,进程 " + pid + " 等待...");
        }
    }
 
    private boolean checkSafety(int pid, int[] request) {
        int numOfProcesses = max.length;
        int numOfResources = available.length;
 
        int[] work = Arrays.copyOf(available, numOfResources);
        boolean[] finish = new boolean[numOfProcesses];
 
        // 设置该进程的请求资源情况
        for (int i = 0; i < numOfResources; i++) {
            allocation[pid][i] += request[i];
            need[pid][i] -= request[i];
            work[i] -= request[i];
        }
 
        int count = 0;   // 用于统计已分配资源的进程数
        boolean hasFinished = true;   // 标识是否存在符合条件的进程
 
        while (count < numOfProcesses && hasFinished) {
            hasFinished = false;
 
            for (int i = 0; i < numOfProcesses; i++) {
                if (!finish[i] && checkNeedLessOrEqual(work, need[i])) {
                    // 分配资源给进程
                    for (int j = 0; j < numOfResources; j++) {
                        work[j] += allocation[i][j];
                    }
                    finish[i] = true;
                    count++;
                    hasFinished = true;
                }
            }
        }
 
        // 恢复该进程的请求资源情况
        for (int i = 0; i < numOfResources; i++) {
            allocation[pid][i] -= request[i];
            need[pid][i] += request[i];
            work[i] += request[i];
        }
 
        return count == numOfProcesses;
    }
 
    private boolean checkNeedLessOrEqual(int[] work, int[] need) {
        for (int i = 0; i < work.length; i++) {
            if (work[i] < need[i]) {
                return false;
            }
        }
        return true;
    }
 
    private void allocateResources(int pid, int[] request) {
        int numOfResources = available.length;
 
        for (int i = 0; i < numOfResources; i++) {
            available[i] -= request[i];
            allocation[pid][i] += request[i];
            need[pid][i] -= request[i];
        }
    }
}
 
public class TestBanker {
    public static void main(String[] args) {
        int[][] max = {
                {7, 5, 3},
                {3, 2, 2},
                {9, 0, 2},
                {2, 2, 2},
                {4, 3, 3}
        };
 
        int[][] allocation = {
                {0, 1, 0},
                {2, 0, 0},
                {3, 0, 2},
                {2, 1, 1},
                {0, 0, 2}
        };
 
        int[] available = {3, 3, 2};
 
        // 继续编写您想要的代码逻辑
    }
}
相关文章
|
1天前
|
算法 Java 索引
【算法】重建二叉树并进行后序遍历的Java实现
【算法】重建二叉树并进行后序遍历的Java实现
11 5
|
1天前
|
算法 Java
[Java·算法·简单] LeetCode 283. 移动零
[Java·算法·简单] LeetCode 283. 移动零
10 2
|
1天前
|
算法 Java
[Java·算法·中等] LeetCode21. 合并两个有序链表
[Java·算法·中等] LeetCode21. 合并两个有序链表
9 2
|
4天前
|
搜索推荐 算法 前端开发
计算机Java项目|基于协同过滤算法的体育商品推荐系统
计算机Java项目|基于协同过滤算法的体育商品推荐系统
|
4天前
|
算法 前端开发 Java
探讨Java中递归构建树形结构的算法
探讨Java中递归构建树形结构的算法
5 1
|
5天前
|
算法 Java
Java中常用hash算法总结
Java中常用hash算法总结
6 0
|
8天前
|
分布式计算 算法 搜索推荐
Java中可以用的大数据推荐算法
在Java中实现大数据推荐算法,通常使用Apache Mahout、Weka、DL4J或Spark MLlib。本文简要介绍了三种推荐算法:基于内容的推荐、协同过滤推荐和深度学习推荐,以及它们的使用场景。提供了每种算法的伪代码或关键代码片段。基于内容的推荐适用于有用户历史行为和物品内容信息的场景,而协同过滤适用于大量用户行为数据的场景,深度学习推荐则用于处理复杂特征。在实现时,注意数据预处理、特征提取、用户画像构建和相似度计算。
14 1
|
11天前
|
缓存 算法 NoSQL
(JAVA)仿拼多多砍价算法
(JAVA)仿拼多多砍价算法
|
13天前
|
算法 Java Go
【经典算法】LeetCode 392 判断子序列(Java/C/Python3/Go实现含注释说明,Easy)
【经典算法】LeetCode 392 判断子序列(Java/C/Python3/Go实现含注释说明,Easy)
15 0
|
1月前
|
存储 算法 Java
【数据结构与算法】1、学习动态数组数据结构(基本模拟实现 Java 的 ArrayList 实现增删改查)
【数据结构与算法】1、学习动态数组数据结构(基本模拟实现 Java 的 ArrayList 实现增删改查)
52 0