題意:要求開6條線程計算累加1 -> 10000000
難點:如何獲取子線程的執行結果並聚合
思路一
生產者-消費者 經典模型:
- 多個生產者負責生產(累加)作業
- 生產者將生產結果存入共享倉庫中
- 消費者(主線程)從共享倉庫中取出結果
/**
* 多線程計算累加數
*/
public class Accumulate {
public static void main(String[] args) {
Storage storage = new Storage();
// 為多個計算器對象創建線程
Thread calThread1 = new Thread(new Calculate(1, storage), "Thread-1");
Thread calThread2 = new Thread(new Calculate(2, storage), "Thread-2");
Thread calThread3 = new Thread(new Calculate(3, storage), "Thread-3");
Thread calThread4 = new Thread(new Calculate(4, storage), "Thread-4");
Thread calThread5 = new Thread(new Calculate(5, storage), "Thread-5");
Thread calThread6 = new Thread(new Calculate(6, storage), "Thread-6");
calThread1.start();
calThread2.start();
calThread3.start();
calThread4.start();
calThread5.start();
calThread6.start();
// 打印最終結果
storage.printTotal();
}
}
/**
* 計算器對象,負責計算start -> end
*/
class Calculate implements Runnable {
private Storage storage;
private long start;
public Calculate(long start, Storage storage) {
this.start = start;
this.storage = storage;
}
@Override
public void run() {
long num = start;
long sum = 0;
while (num <= 10000000) {
System.out.println(Thread.currentThread().getName() + " add num " + num);
sum += num;
num += 6;
}
// 線程計算完畢, 調用累加器進行累加
storage.push(sum);
}
}
/**
* 倉庫對象,負責累加
*/
class Storage {
private long total = 0;
private int count = 0;
public synchronized void push(long sum) {
total += sum;
count++;
notifyAll();
}
public synchronized void printTotal() {
while (count < 6) {
try {
System.out.println(Thread.currentThread().getName() + " is wait");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("storage result = " + total);
}
}
思路二
線程異步返回:
- 利用線程池並發處理多個任務
- 使用Future+Callable獲取異步執行結果
- 待線程池中所有任務結束,計算累加結果
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.*;
/**
* 線程池計算累加數
*/
public class Accumulate {
public static void main(String[] args) {
// 建立線程池 與 動態結果數組
ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(6);
List<Future<Long>> resultList = new ArrayList<>();
// 定義10個任務分別負責一定范圍內的元素累計
for (int i = 0; i < 10; i++) {
CalTask calTask = new CalTask(i*100000000+1, (i+1)*100000000);
Future<Long> result = executor.submit(calTask);
resultList.add(result);
}
// 每隔50毫秒遍歷一遍所有動態結果,直到所有任務執行完畢
do {
System.out.printf("Main: 已經完成多少個任務: %d\n",executor.getCompletedTaskCount());
for (int i = 0; i < resultList.size(); i++) {
Future<Long> result = resultList.get(i);
System.out.printf("Main: Task %d is %s\n",i,result.isDone());
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
} while (executor.getCompletedTaskCount() < resultList.size());
// 若所有任務執行完畢,則對執行結果進行累計
long total = 0;
for (int i = 0; i < resultList.size(); i++) {
Future<Long> result = resultList.get(i);
long sum = 0;
try {
sum = result.get();
total += sum;
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
System.out.printf("total is: %d\n", total);
executor.shutdown();
}
}
class CalTask implements Callable<Long> {
private int startNum;
private int endNum;
public CalTask(int startNum, int endNum) {
this.startNum = startNum;
this.endNum = endNum;
}
@Override
public Long call() throws Exception {
long sum = 0;
for (int i = startNum; i <= endNum; i++) {
sum += i;
}
Thread.sleep(new Random().nextInt(100));
System.out.printf("%s: %d\n", Thread.currentThread().getName(), sum);
return sum;
}
}