Java多執行緒加法計算
阿新 • • 發佈:2021-02-08
技術標籤:多執行緒future併發程式設計cephthread
題意:要求開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; } }