银行家算法是一种 死锁避免(Deadlock Avoidance) 算法,它用于 动态分配系统资源,确保系统始终处于 安全状态(Safe State),避免进入死锁。
本篇博客将深入讲解:
- 银行家算法的核心概念
- 算法的执行步骤(含示例)
- Java 实现银行家算法
- 银行家算法的优势与局限性
1. 银行家算法的核心概念
1.1 什么是银行家算法?
银行家算法由 Edsger Dijkstra 提出,它的名字来源于 银行借贷系统:
银行不会一次性把所有资金借给客户,而是保证即使有客户申请贷款,银行仍能满足所有客户的最低需求,以防止资金枯竭。
同理,在计算机资源分配中:
- 进程向系统申请资源时,银行家算法会先检查资源是否足够。
- 如果满足条件,系统会假设分配资源后仍处于安全状态,才会真正分配。
- 如果分配资源会导致系统进入不安全状态,则拒绝该申请。
1.2 关键术语
银行家算法中,主要涉及以下数据结构:
名称 | 作用 |
---|---|
Max | 进程需要的最大资源数 |
Allocation | 进程当前已分配的资源 |
Need | 进程仍需要的资源 = Max - Allocation |
Available | 系统当前可用的资源 |
假设系统有 3 类资源 A、B、C,现有 5 个进程(P0 ~ P4),初始资源情况如下:
资源状态
资源类型 | A | B | C |
---|---|---|---|
Available(当前可用) | 3 | 3 | 2 |
进程的最大需求(Max)
进程 | A | B | C |
---|---|---|---|
P0 | 7 | 5 | 3 |
P1 | 3 | 2 | 2 |
P2 | 9 | 0 | 2 |
P3 | 2 | 2 | 2 |
P4 | 4 | 3 | 3 |
进程当前已分配的资源(Allocation)
进程 | A | B | C |
---|---|---|---|
P0 | 0 | 1 | 0 |
P1 | 2 | 0 | 0 |
P2 | 3 | 0 | 2 |
P3 | 2 | 1 | 1 |
P4 | 0 | 0 | 2 |
进程仍需要的资源(Need = Max - Allocation)
进程 | A | B | C |
---|---|---|---|
P0 | 7 | 4 | 3 |
P1 | 1 | 2 | 2 |
P2 | 6 | 0 | 0 |
P3 | 0 | 1 | 1 |
P4 | 4 | 3 | 1 |
2. 银行家算法的执行步骤
2.1 资源分配步骤
- 检查请求是否超过 Need
- 若
Request ≤ Need
,继续,否则出错(进程请求超过最大需求)。
- 若
- 检查请求是否超过 Available
- 若
Request ≤ Available
,则继续,否则进程需等待资源释放。
- 若
- 尝试分配资源
- 临时分配
Available -= Request
,Allocation += Request
,Need -= Request
。
- 临时分配
- 安全性检测
- 检查分配后是否能找到一个安全序列。
- 若有安全序列,则分配成功,否则回滚。
2.2 安全性检测步骤
- 标记所有进程为未完成(Finish = false)。
- 找到一个进程
Pi
,使得Need[i] ≤ Available
。 - 假设分配资源给
Pi
,执行完后释放Pi
的资源(Available += Allocation[i])。 - 重复 2-3,直到所有进程都能执行完毕,即
Finish[i] = true
。 - 若所有进程都完成,则系统安全,否则回滚请求。
3. Java 实现银行家算法
import java.util.Arrays;
public class BankersAlgorithm {
private final int P; // 进程数量
private final int R; // 资源种类数量
private int[] available; // 可用资源
private int[][] max; // 最大需求矩阵
private int[][] allocation; // 已分配矩阵
private int[][] need; // 仍需资源矩阵
public BankersAlgorithm(int P, int R, int[] available, int[][] max, int[][] allocation) {
this.P = P;
this.R = R;
this.available = available;
this.max = max;
this.allocation = allocation;
this.need = new int[P][R];
// 计算 Need = Max - Allocation
for (int i = 0; i < P; i++) {
for (int j = 0; j < R; j++) {
need[i][j] = max[i][j] - allocation[i][j];
}
}
}
// 安全性检查
private boolean isSafe() {
int[] work = Arrays.copyOf(available, R);
boolean[] finish = new boolean[P];
int count = 0;
while (count < P) {
boolean found = false;
for (int i = 0; i < P; i++) {
if (!finish[i]) {
boolean canExecute = true;
for (int j = 0; j < R; j++) {
if (need[i][j] > work[j]) {
canExecute = false;
break;
}
}
if (canExecute) {
for (int j = 0; j < R; j++) {
work[j] += allocation[i][j];
}
finish[i] = true;
found = true;
count++;
}
}
}
if (!found) return false;
}
return true;
}
// 资源请求
public boolean requestResources(int processId, int[] request) {
for (int i = 0; i < R; i++) {
if (request[i] > need[processId][i] || request[i] > available[i]) {
return false;
}
}
for (int i = 0; i < R; i++) {
available[i] -= request[i];
allocation[processId][i] += request[i];
need[processId][i] -= request[i];
}
if (isSafe()) {
return true;
} else {
for (int i = 0; i < R; i++) {
available[i] += request[i];
allocation[processId][i] -= request[i];
need[processId][i] += request[i];
}
return false;
}
}
public static void main(String[] args) {
int P = 5, R = 3;
int[] available = {3, 3, 2};
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}};
BankersAlgorithm ba = new BankersAlgorithm(P, R, available, max, allocation);
System.out.println("系统是否安全: " + ba.isSafe());
}
}
总结
银行家算法可以 有效避免死锁,但计算复杂度较高,适用于静态资源分配场景。在实际应用中,现代操作系统更倾向于 死锁检测与资源抢占机制。🚀