自我感觉良好的死循环妙用:多线程协作

还未曾想过死循环的条件break机制能在流程控制以外的场景中焕发光彩。


问题描述

有四个线程,每个线程函数都能够接收三个整型变量(变量的值在创建线程时设定),在线程内部求出三个变量的和,在四个线程都计算完毕后,要求必须在main函数中对四个线程的计算结果再次求出总和,然后在各个线程中分别输出这个总和值。

方案逻辑

程序开始运行后,主线程与子线程的协作可以这样描述:

  1. 子线程计算变量之和,主线程进入死循环,检测子线程是否计算完成。
  2. 子线程计算完成时,主线程计算总和并跳出循环,此时子线程进入死循环,检测主线程是否计算完成。
  3. 主线程计算完成后即结束运行,各个子线程输出总和。
步骤 主线程 子线程
启动,初始化数据
循环等待子线程通知 启动,各子线程计算变量之和
循环等待
各子线程计算完毕后通知主线程
跳出循环
对子线程结果再次求和
通知子线程
跳出循环
循环等待主线程通知
结束 输出结果
跳出循环
结束

两种检测都各需要一个flag作为判断条件,而且需要一个共享的空间用于保存子线程和主线程计算的结果,在需要取用时从中获取即可。

实现代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Main.java
public class Main {
public static void main(String[] args) {
Thread[] thread = new Thread[4];
for (int i = 1; i <= thread.length; i++)
thread[i - 1] = new Thread(new Task(i, i, i));
for (int i = 1; i <= thread.length; i++)
thread[i - 1].start();
while (true) {
if (Data.isSubFinished()) {
for (int sub : Data.getArrayList())
Data.setSum(Data.getSum() + sub);
Data.finishSum();
break;
}
}
}
}
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
// Task.java
public class Task implements Runnable {
private final int a;
private final int b;
private final int c;

public Task(int a, int b, int c) {
this.a = a;
this.b = b;
this.c = c;
}

@Override
public void run() {
int sum = a + b + c;
Data.addList(sum);
while (true) {
if (Data.getListLength() == 4) {
Data.finishSub();
break;
}
}
while (true) {
if (Data.isSumFinished()) {
System.out.println(
"In " +
Thread.currentThread().getName() +
", the sum is: " + Data.getSum()
);
break;
}
}
}
}
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
public class Data {
private static final ArrayList<Integer> arrayList = new ArrayList<>();
private static int sum = 0;
private static boolean flagSub = false;
private static boolean flagSum = false;

public static synchronized void addList(Integer sum) {
arrayList.add(sum);
}

public static ArrayList<Integer> getArrayList() {
return arrayList;
}

public static int getListLength() {
return arrayList.size();
}

public static void setSum(int sum) {
Data.sum = sum;
}

public static int getSum() {
return sum;
}

public static void finishSub() {
flagSub = true;
}

public static void finishSum(){
flagSum = true;
}

public static boolean isSubFinished() {
return flagSub;
}

public static boolean isSumFinished() {
return flagSum;
}
}

运行结果

1
2
3
4
In Thread-1, the sum is: 30
In Thread-0, the sum is: 30
In Thread-3, the sum is: 30
In Thread-2, the sum is: 30

自我感觉良好的死循环妙用:多线程协作
https://skycurtain.github.io/2022/05/21/charm-of-endless-loop-in-multithreading/
作者
Skycurtain
发布于
2022年5月21日
许可协议