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月前
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
69 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
3月前
|
负载均衡 NoSQL 算法
一天五道Java面试题----第十天(简述Redis事务实现--------->负载均衡算法、类型)
这篇文章是关于Java面试中Redis相关问题的笔记,包括Redis事务实现、集群方案、主从复制原理、CAP和BASE理论以及负载均衡算法和类型。
一天五道Java面试题----第十天(简述Redis事务实现--------->负载均衡算法、类型)
|
3月前
|
搜索推荐 算法 Java
手写快排:教你用Java写出高效排序算法!
快速排序(QuickSort)是经典的排序算法之一,基于分治思想,平均时间复杂度为O(n log n),广泛应用于各种场合。在这篇文章中,我们将手写一个Java版本的快速排序,从基础实现到优化策略,并逐步解析代码背后的逻辑。
147 1
|
1月前
|
算法 搜索推荐 Java
java 后端 使用 Graphics2D 制作海报,画echarts图,带工具类,各种细节:如头像切割成圆形,文字换行算法(完美实验success),解决画上文字、图片后不清晰问题
这篇文章介绍了如何使用Java后端技术,结合Graphics2D和Echarts等工具,生成包含个性化信息和图表的海报,并提供了详细的代码实现和GitHub项目链接。
105 0
java 后端 使用 Graphics2D 制作海报,画echarts图,带工具类,各种细节:如头像切割成圆形,文字换行算法(完美实验success),解决画上文字、图片后不清晰问题
|
1月前
|
算法 Java Linux
java制作海报一:java使用Graphics2D 在图片上写字,文字换行算法详解
这篇文章介绍了如何在Java中使用Graphics2D在图片上绘制文字,并实现自动换行的功能。
100 0
|
1月前
|
算法 Java 测试技术
数据结构 —— Java自定义代码实现顺序表,包含测试用例以及ArrayList的使用以及相关算法题
文章详细介绍了如何用Java自定义实现一个顺序表类,包括插入、删除、获取数据元素、求数据个数等功能,并对顺序表进行了测试,最后还提及了Java中自带的顺序表实现类ArrayList。
21 0
|
3月前
|
设计模式 缓存 算法
揭秘策略模式:如何用Java设计模式轻松切换算法?
【8月更文挑战第30天】设计模式是解决软件开发中特定问题的可重用方案。其中,策略模式是一种常用的行为型模式,允许在运行时选择算法行为。它通过定义一系列可互换的算法来封装具体的实现,使算法的变化与客户端分离。例如,在电商系统中,可以通过定义 `DiscountStrategy` 接口和多种折扣策略类(如 `FidelityDiscount`、`BulkDiscount` 和 `NoDiscount`),在运行时动态切换不同的折扣逻辑。这样,`ShoppingCart` 类无需关心具体折扣计算细节,只需设置不同的策略即可实现灵活的价格计算,符合开闭原则并提高代码的可维护性和扩展性。
63 2
|
3月前
|
安全 算法 Java
java系列之~~网络通信安全 非对称加密算法的介绍说明
这篇文章介绍了非对称加密算法,包括其定义、加密解密过程、数字签名功能,以及与对称加密算法的比较,并解释了非对称加密在网络安全中的应用,特别是在公钥基础设施和信任网络中的重要性。
|
3月前
|
存储 算法 Java
LeetCode经典算法题:打家劫舍java详解
LeetCode经典算法题:打家劫舍java详解
70 2
|
3月前
|
数据采集 搜索推荐 算法
【高手进阶】Java排序算法:从零到精通——揭秘冒泡、快速、归并排序的原理与实战应用,让你的代码效率飙升!
【8月更文挑战第21天】Java排序算法是编程基础的重要部分,在算法设计与分析及实际开发中不可或缺。本文介绍内部排序算法,包括简单的冒泡排序及其逐步优化至高效的快速排序和稳定的归并排序,并提供了每种算法的Java实现示例。此外,还探讨了排序算法在电子商务、搜索引擎和数据分析等领域的广泛应用,帮助读者更好地理解和应用这些算法。
42 0