用Java实现银行家算法

实验目的

银行家算法是避免死锁的一种重要方法,本实验要求用高级语言编写和调试一个简单的银行家算法程序。加深了解有关资源申请、避免死锁等概念,并体会和了解死锁和避免死锁的具体实施方法。

实验内容

1)设计进程对各类资源最大申请表示及初值确定。
2)设定系统提供资源初始状况。
3)设定每次某个进程对各类资源的申请表示。
4)编制程序,依据银行家算法,决定其申请是否得到满足。

代码解释

Banker类-T0时刻资源分配

进行变量定义:
对进程数量M,资源种类数量N,各资源总数All[],m个进程对n类资源的最大需求量Max[][],m个进程已经得到n类资源的资源量Allocation[][],m个进程还需要n类资源的资源量Need[][],系统可用资源数系统可用资源数Available[][]。还有一个进程完成标志位Finish[]。

1
2
3
4
5
6
7
8
9
10
11
12
13
class Banker{

int ID[], //进程代号
M, //m个进程
N, //n类资源
All[], //系统各资源数量
Max[][], //m个进程对n类资源的最大需求量
Allocation[][], //m个进程已经得到n类资源的资源量
Need[][], //m个进程还需要n类资源的资源量
Available[][]; //系统可用资源数

boolean Finish[]; //标记进程是否完成
int a=0;//Available的第一个下标

无参构造函数:
在无参函数中进行变量的初始化,需要手动输入的变量为M,N,All[],Max[][],Allocation[][]。
当输入了初始值后,Need[][]和Available[][]就可以通过need 的计算公式:
Need=[i][j]= Max[i][j]- Allocation[i][j]
Available[][]:Available[a][n] = All[n] - Allocation[m][n](遍历)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public Banker() {	//无参构造器
@SuppressWarnings("resource")
Scanner input = new Scanner(System.in);
System.out.println("请输入进程数");
M = input.nextInt();//m个进程
System.out.println("请输入资源种类数");
N = input.nextInt();//n类资源
//初始化数组
ID = new int[M]; //进程代号
All = new int[N]; //系统各资源数量
Max = new int[M][N]; //m个进程对n类资源的最大需求量
Allocation = new int[M][N]; //m个进程已经得到n类资源的资源量
Need = new int[M][N]; //m个进程还需要n类资源的资源量
Available = new int[M+1][N]; //系统可用资源数
Finish = new boolean[M]; //标记进程是否完成
System.out.println("请输入系统初始可用资源数");
for(int i=0; i<N; i++)//系统初始可用资源数
All[i] = input.nextInt();
System.out.println("请输入"+M+"个进程对"+N+"类资源的最大需求量");
for(int i=0; i<M; i++){//m个进程对n类资源的最大需求量
ID[i] = i;
for(int j=0; j<N; j++)
Max[i][j] = input.nextInt();
}
System.out.println("请输入"+M+"个进程已经得到的"+N+"类资源的资源量");
for(int i=0; i<M; i++) //m个进程已经得到n类资源的资源量
for(int j=0; j<N; j++)
Allocation[i][j] = input.nextInt();
Need_Resources();
Available_Resources();
Print_Banker();
}

初始化Need和Available矩阵:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private void Need_Resources() {//初始化Need矩阵
// TODO Auto-generated method stub
for(int i=0; i<M; i++)//m个进程还需要n类资源的资源量
for(int j=0; j<N; j++)
Need[i][j] = Max[i][j] - Allocation[i][j];
}

private void Available_Resources() {//更新系统当前可用资源数
// TODO Auto-generated method stub
for(int n=0; n<N; n++){//系统目前可用资源数
Available[a][n] = All[n];
for(int m=0; m<M; m++){
Available[a][n] -= Allocation[m][n];
}
}
}

就此,所有矩阵初始化完毕,对T0时刻的资源分配图进行打印,如图所示:
运行截图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
private void Print_Banker() {//T0时刻的资源分配图
System.out.println("\nT0时刻资源分配图:");
System.out.print("资源\t资源数量\n");
for(int i=0; i<N; i++)
System.out.printf("S%d\t%d\n", i, All[i]);
System.out.print("\n进程\t Max\tAllocation\tNeed\tAvailable\tFinish\n");
for(int i=0; i<M; i++){
System.out.print("P"+ID[i]);
System.out.print("\t");
for(int j=0; j<Max[ID[i]].length; j++){
System.out.printf("%d ", Max[ID[i]][j]);
}
System.out.print("\t");
for(int j=0; j<Allocation[ID[i]].length; j++){
System.out.printf("%d ", Allocation[ID[i]][j]);
}
System.out.print("\t\t");
for(int j=0; j<Need[ID[i]].length; j++){
System.out.printf("%d ", Need[ID[i]][j]);
}
System.out.print("\t");
if(i == 0){
for(int j=0; j<N; j++){
System.out.printf("%d ", Available[i][j]);
}
}
System.out.print("\t");
System.out.print("\t");
System.out.print(Finish[i]);
System.out.println();
}
}

安全性检查

对T0时刻资源分配情况进行安全性分析,为每个进程进行可满足性检查。
Need[i][j] > Available[a][j]
遍历每个资源,都满足可满足性,则进入试分配,若不满足,将该进程的标志位flag2置为false,跳出for循环。试分配,先将进程的Finish标志位置为true,代表这个进程已经被分配资源执行完毕。
更新Available:
Available[a][j] = Available[a-1][j] + Allocation[i][j];
当所有进程都通过试分配(a == M)后,打印分配过资源的安全序列Print_Banker_Se()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public void Security_examine(){//安全性检测
boolean flag1, //所有进程
flag2; //每个进程
flag1 = true;
while(flag1){
flag1 = false;
for(int i=0; i<M; i++){
flag2 = true;
for(int j=0; flag2 && j<N; j++){
if(Need[i][j] > Available[a][j] || Finish[i]){//存在一个条件不满足或者该进程已经完成
flag2 = false;
}
}
if(flag2 && !Finish[i]){//该进程(第i个进程)可执行
flag1 = true;
Finish[i] = true;
ID[a] = i;
a++;//以此判断所有进程是否都执行,安全检查
for(int j=0; flag2 && j<N; j++){
Available[a][j] = Available[a-1][j] + Allocation[i][j];
}
}
}
}
System.out.println("\nT0时刻的安全性:");
if(a == M){
Print_Banker_Se();
System.out.println("\n安全序列:");
for(int i=0; i<M; i++){
System.out.print("->P"+ID[i]);
}
System.out.println("\n");
}
else{
System.out.println("系统不安全");
}
}

Banker类-银行家算法

申请资源:某个进程发起请求向量Request(,,*),系统按银行家算法进行检查。
① Request[i] > Need[n][i]
② Request[i] > Available[0][i]
满足以上两条说明不满足正确性检查和可满足性检查,将标志位flag置为false,报告分配不安全。
若通过了正确性和可满足性检测就将这条进程的已分配Allocation加上申请量,并重新对Need和Available矩阵进行新的初始化。并打印此时初状态资源分配表。

安全性检查:
通过主程序调用键盘输入控制进入安全性检查部分,思想和源码与T0时刻的安全性检查雷同,再次不在赘述。安全性检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public void Reallocation(){//申请资源
@SuppressWarnings("resource")
Scanner input = new Scanner(System.in);
int[] Request = new int[N];
boolean flag = true;
System.out.print("\n输入进程代号:");
int n = input.nextInt();
System.out.print("输入请求资源数:");
for(int j=0; j<N; j++)
Request[j] = input.nextInt();
for(int i=0; i<N; i++){//合理性检查,可用性检查
if(Request[i] > Need[n][i] || Request[i] > Available[0][i])
flag = false;
}
if(flag){
for(int i=0; i<N; i++){
Allocation[n][i] += Request[i];
}
Init();
Print_Banker();
}
else{
System.out.println("分配不安全\n");
}
}

private void Init() {
// TODO Auto-generated method stub
a = 0;
Need_Resources();//再次初始化
Available_Resources();
for(int i=0; i<M; i++){//ID初始化
ID[i] = i;
Finish[i] = false;
}
}

主函数

使用无参构造器new了一个banker对象,打印菜单,并控制调用安全性检测、银行家算法(请求再分配资源)以及退出。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class TestBankerClass {
public static void main(String[] args) {
// TODO Auto-generated method stub
Banker banker = new Banker();
int n;
boolean flag=true;
Scanner input = new Scanner(System.in);
System.out.println("\n*************菜单****************");
System.out.println("进行安全性检查:1\n请求再分配资源:2\n退出:其他");
System.out.println("*********************************");
while(flag){
System.out.print("输入操作代号:");
n = input.nextInt();
switch(n){
case 1: banker.Security_examine();break;
case 2: banker.Reallocation();break;
default:flag = false;
System.out.print("\n操作结束!!!!");
}
}
input.close();//关闭流
}
}

输入示例

例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
初始化:
5
3
10 5 7

7 5 3
3 2 2
9 0 2
2 2 2
4 3 3

0 1 0
2 0 0
3 0 2
2 1 1
0 0 2

再分配:
1
1 0 2

4
3 3 0

0
0 2 0

例2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
初始化:
3
3
10 8 7
8 7 5
5 2 5
6 6 2

3 2 0
2 0 2
1 3 2

再分配:
0
1 0 0

1
0 1 1

运行结果

例1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
T0时刻资源分配图:
资源 资源数量
S0 10
S1 5
S2 7

进程 Max Allocation Need Available Finish
P0 7 5 3 0 1 0 7 4 3 3 3 2 false
P1 3 2 2 2 0 0 1 2 2 false
P2 9 0 2 3 0 2 6 0 0 false
P3 2 2 2 2 1 1 0 1 1 false
P4 4 3 3 0 0 2 4 3 1 false

*************菜单****************
进行安全性检查:1
请求再分配资源:2
退出:其他
*********************************
输入操作代号:1

T0时刻的安全性:

进程 Work Need Allocation Work+Allocation Finish
P1 3 3 2 1 2 2 2 0 0 5 3 2 true
P3 5 3 2 0 1 1 2 1 1 7 4 3 true
P4 7 4 3 4 3 1 0 0 2 7 4 5 true
P0 7 4 5 7 4 3 0 1 0 7 5 5 true
P2 7 5 5 6 0 0 3 0 2 10 5 7 true

安全序列:
->P1->P3->P4->P0->P2

输入操作代号:2

输入进程代号:1
输入请求资源数:1 0 2

T0时刻资源分配图:
资源 资源数量
S0 10
S1 5
S2 7

进程 Max Allocation Need Available Finish
P0 7 5 3 0 1 0 7 4 3 2 3 0 false
P1 3 2 2 3 0 2 0 2 0 false
P2 9 0 2 3 0 2 6 0 0 false
P3 2 2 2 2 1 1 0 1 1 false
P4 4 3 3 0 0 2 4 3 1 false
输入操作代号:1

T0时刻的安全性:

进程 Work Need Allocation Work+Allocation Finish
P1 2 3 0 0 2 0 3 0 2 5 3 2 true
P3 5 3 2 0 1 1 2 1 1 7 4 3 true
P4 7 4 3 4 3 1 0 0 2 7 4 5 true
P0 7 4 5 7 4 3 0 1 0 7 5 5 true
P2 7 5 5 6 0 0 3 0 2 10 5 7 true

安全序列:
->P1->P3->P4->P0->P2

输入操作代号:2

输入进程代号:4
输入请求资源数:3 3 0
分配不安全

输入操作代号:1

T0时刻的安全性:

进程 Work Need Allocation Work+Allocation Finish
P1 2 3 0 0 2 0 3 0 2 5 3 2 true
P3 5 3 2 0 1 1 2 1 1 7 4 3 true
P4 7 4 3 4 3 1 0 0 2 7 4 5 true
P0 7 4 5 7 4 3 0 1 0 7 5 5 true
P2 7 5 5 6 0 0 3 0 2 10 5 7 true

安全序列:
->P1->P3->P4->P0->P2

输入操作代号:2

输入进程代号:0
输入请求资源数:0 2 0

T0时刻资源分配图:
资源 资源数量
S0 10
S1 5
S2 7

进程 Max Allocation Need Available Finish
P0 7 5 3 0 3 0 7 2 3 2 1 0 false
P1 3 2 2 3 0 2 0 2 0 false
P2 9 0 2 3 0 2 6 0 0 false
P3 2 2 2 2 1 1 0 1 1 false
P4 4 3 3 0 0 2 4 3 1 false
输入操作代号:1

T0时刻的安全性:
系统不安全
输入操作代号:4

操作结束!!!!

完整代码

TestBankerClass类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package bankerTest;

import java.util.Scanner;

public class TestBankerClass {
public static void main(String[] args) {
// TODO Auto-generated method stub
Banker banker = new Banker();
int n;
boolean flag=true;
Scanner input = new Scanner(System.in);
System.out.println("\n*************菜单****************");
System.out.println("进行安全性检查:1\n请求再分配资源:2\n退出:其他");
System.out.println("*********************************");
while(flag){
System.out.print("输入操作代号:");
n = input.nextInt();
switch(n){
case 1: banker.Security_examine();break;
case 2: banker.Reallocation();break;
default:flag = false;
System.out.print("\n操作结束!!!!");
}
}
input.close();//关闭流
}
}

Banker类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
package bankerTest;

import java.util.Scanner;

class Banker{
//定义数组
int ID[], //进程代号
M, //m个进程
N, //n类资源
All[], //系统各资源数量
Max[][], //m个进程对n类资源的最大需求量
Allocation[][], //m个进程已经得到n类资源的资源量
Need[][], //m个进程还需要n类资源的资源量
Available[][]; //系统可用资源数
boolean Finish[]; //标记进程是否完成
int a=0; //Available的第一个下标

public Banker() { //无参构造器
@SuppressWarnings("resource")//忽视输入流未关闭的报错
Scanner input = new Scanner(System.in);
System.out.println("请输入进程数");
M = input.nextInt();//m个进程
System.out.println("请输入资源种类数");
N = input.nextInt();//n类资源
//初始化数组
ID = new int[M]; //进程代号
All = new int[N]; //系统各资源数量
Max = new int[M][N]; //m个进程对n类资源的最大需求量
Allocation = new int[M][N]; //m个进程已经得到n类资源的资源量
Need = new int[M][N]; //m个进程还需要n类资源的资源量
Available = new int[M+1][N]; //系统可用资源数
Finish = new boolean[M]; //标记进程是否完成
System.out.println("请输入系统初始可用资源数");
for(int i=0; i<N; i++)//系统初始可用资源数
All[i] = input.nextInt();
System.out.println("请输入"+M+"个进程对"+N+"类资源的最大需求量");
for(int i=0; i<M; i++){//m个进程对n类资源的最大需求量
ID[i] = i;
for(int j=0; j<N; j++)
Max[i][j] = input.nextInt();
}
System.out.println("请输入"+M+"个进程已经得到的"+N+"类资源的资源量");
for(int i=0; i<M; i++) //m个进程已经得到n类资源的资源量
for(int j=0; j<N; j++)
Allocation[i][j] = input.nextInt();
Need_Resources();
Available_Resources();
Print_Banker();
}

private void Need_Resources() {//初始化Need矩阵
// TODO Auto-generated method stub
for(int i=0; i<M; i++)//m个进程还需要n类资源的资源量
for(int j=0; j<N; j++)
Need[i][j] = Max[i][j] - Allocation[i][j];
}

private void Available_Resources() {//更新系统当前可用资源数
// TODO Auto-generated method stub
for(int n=0; n<N; n++){//系统目前可用资源数
Available[a][n] = All[n];
for(int m=0; m<M; m++){
Available[a][n] -= Allocation[m][n];
}
}
}

private void Print_Banker() {//T0时刻的资源分配图
System.out.println("\nT0时刻资源分配图:");
System.out.print("资源\t资源数量\n");
for(int i=0; i<N; i++)
System.out.printf("S%d\t%d\n", i, All[i]);
System.out.print("\n进程\t Max\tAllocation\tNeed\tAvailable\tFinish\n");
for(int i=0; i<M; i++){
System.out.print("P"+ID[i]);
System.out.print("\t");
for(int j=0; j<Max[ID[i]].length; j++){
System.out.printf("%d ", Max[ID[i]][j]);
}
System.out.print("\t");
for(int j=0; j<Allocation[ID[i]].length; j++){
System.out.printf("%d ", Allocation[ID[i]][j]);
}
System.out.print("\t\t");
for(int j=0; j<Need[ID[i]].length; j++){
System.out.printf("%d ", Need[ID[i]][j]);
}
System.out.print("\t");
if(i == 0){
for(int j=0; j<N; j++){
System.out.printf("%d ", Available[i][j]);
}
}
System.out.print("\t");
System.out.print("\t");
System.out.print(Finish[i]);
System.out.println();
}
}

public void Security_examine(){//安全性检测
boolean flag1, //所有进程
flag2; //每个进程
flag1 = true;
while(flag1){
flag1 = false;
for(int i=0; i<M; i++){
flag2 = true;
for(int j=0; flag2 && j<N; j++){
if(Need[i][j] > Available[a][j] || Finish[i]){//存在一个条件不满足或者该进程已经完成
flag2 = false;
}
}
if(flag2 && !Finish[i]){//该进程(第i个进程)可执行
flag1 = true;
Finish[i] = true;
ID[a] = i;
a++;//以此判断所有进程是否都执行,安全检查
for(int j=0; flag2 && j<N; j++){
Available[a][j] = Available[a-1][j] + Allocation[i][j];
}
}
}
}
System.out.println("\nT0时刻的安全性:");
if(a == M){
Print_Banker_Se();
System.out.println("\n安全序列:");
for(int i=0; i<M; i++){
System.out.print("->P"+ID[i]);
}
System.out.println("\n");
}
else{
System.out.println("系统不安全");
}
}

public void Reallocation(){//申请资源
@SuppressWarnings("resource")
Scanner input = new Scanner(System.in);
int[] Request = new int[N];
boolean flag = true;
System.out.print("\n输入进程代号:");
int n = input.nextInt();
System.out.print("输入请求资源数:");
for(int j=0; j<N; j++)
Request[j] = input.nextInt();
for(int i=0; i<N; i++){//合理性检查,可用性检查
if(Request[i] > Need[n][i] || Request[i] > Available[0][i])
flag = false;
}
if(flag){
for(int i=0; i<N; i++){
Allocation[n][i] += Request[i];
}
Init();
Print_Banker();
}
else{
System.out.println("分配不安全\n");
}
}

private void Init() {
// TODO Auto-generated method stub
a = 0;
Need_Resources();//再次初始化
Available_Resources();
for(int i=0; i<M; i++){//ID初始化
ID[i] = i;
Finish[i] = false;
}
}

private void Print_Banker_Se() {
System.out.print("\n进程\t Work\tNeed\tAllocation\tWork+Allocation\tFinish\n");
for(int i=0; i<M; i++){
System.out.print("P"+ID[i]);
System.out.print("\t");
for(int j=0; j<Available[i].length; j++){
System.out.printf("%d ", Available[i][j]);
}
System.out.print("\t");
for(int j=0; j<Need[ID[i]].length; j++){
System.out.printf("%d ", Need[ID[i]][j]);
}
System.out.print("\t");
for(int j=0; j<Allocation[ID[i]].length; j++){
System.out.printf("%d ", Allocation[ID[i]][j]);
}
System.out.print("\t\t");
for(int j=0; j<Available[i+1].length; j++){
System.out.printf("%d ", Available[i+1][j]);
}
System.out.print("\t");
System.out.print("\t");
System.out.print(Finish[i]);
System.out.println();
}
}
}