Java使用5個線程計算數組之和
前言
之前寫過多線程累加計數,原理跟本篇類似,傳送門
累加計數比計算數組之和邏輯稍微簡單一點,如果對於這塊不熟悉的,可以先看下累加計數。
基本思想已經在之前那篇文章裡寫過瞭,這裡就直接貼代碼瞭。
這裡分別通過自己創建線程來實現功能,還有通過線程池來實現功能。思想都差不多。隻是代碼寫法略有不同。僅供參考。
代碼一:
五個線程交替累加計算數組之和,這種方法其實不如單線程直接累加快,因為交替累加需要前一個線程計算的結果。
package test; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class FiveThreadCount { private int count=0; private int[] arr={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}; private int j=0; //定義一個任務,關鍵點所在 private class MyThread extends Thread{ @Override public void run() { super.run(); while(j<arr.length) { synchronized (MyThread.class) { if(j>=arr.length){ return; } count+=arr[j++]; try { Thread.sleep(100); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); } } } } //方法一 public void test1(){ for(int i=0;i<5;i++){ new MyThread().start(); } try { Thread.sleep(10000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(count); } //方法二 public void test2(){ Thread myThread=new MyThread(); for(int i=0;i<5;i++){ new Thread(myThread).start(); } try { Thread.sleep(10000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(count); } //方法一的線程池實現版 public void test3(){ ExecutorService service=Executors.newCachedThreadPool(); for(int i=0;i<5;i++){ service.execute(new MyThread()); } try { Thread.sleep(10000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(count); } //方法二的線程池實現版 public void test4(){ ExecutorService service=Executors.newCachedThreadPool(); Thread myThread=new MyThread(); for(int i=0;i<5;i++){ service.execute(myThread); } try { Thread.sleep(10000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(count); } }
上邊代碼中,用到瞭sleep方法的原因,sleep(100)是為瞭讓其他線程有時間執行任務,如果不sleep的話,有可能一個線程就全部執行完瞭。 最後的sleep(10000)是為瞭等所有線程執行完後,打印最後的計算結果。
代碼二:
將數組分為5等分,讓每個線程計算自己負責的那份,並發計算,最後匯總結果。這種方式比代碼一速度會快些。因為線程獨立計算,不依賴其他線程的結果。最後幾個線程將總數累加即可。
方式一:
使用Callable,FutureTask方式,來實現代碼:
package test; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.FutureTask; public class FiveThreadCount2 { private int[] arr={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}; private int total=0; public void test() throws InterruptedException, ExecutionException{ ExecutorService service=Executors.newFixedThreadPool(5); int length=arr.length; for(int j=0;j<length;j+=(length/5)){ FutureTask<Integer> task; if( (j+(length/5))<length){ task=new FutureTask<Integer>(new MyCallable(arr, j, j+(length/5))); }else{ task=new FutureTask<Integer>(new MyCallable(arr, j, length)); } service.execute(task); total+=task.get(); } service.shutdown(); System.out.println(total); } public class MyCallable implements Callable<Integer>{ int[] arr; int startIndex; int endIndex; public MyCallable(int[] arr,int startIndex,int endIndex){ this.arr=arr; this.startIndex=startIndex; this.endIndex=endIndex; } @Override public Integer call() throws Exception { int sum=0; for(int i=startIndex;i<endIndex;i++){ sum+=arr[i]; } System.out.println(Thread.currentThread().getName()); return sum; } } }
這個方式有一個缺點,看似5個線程異步執行,其實是順序執行,因為 task.get是要等待線程執行完畢才會執行下邊的代碼。所以效率不會高,可能換種寫法可以解決這個問題,這裡就不深入研究。
方式二:
通過java工具類CountDownLatch實現並發計算
package test; import java.util.concurrent.CountDownLatch; public class FiveThreadCount3 { private int[] arr={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}; private int total=0; public void test() throws InterruptedException{ int length=arr.length; CountDownLatch latch=new CountDownLatch(length%5==0?5:6); System.out.println(length); for(int j=0;j<length;j+=(length/5)){ MyThread task; if( (j+(length/5))<=length){ task=new MyThread(arr, j, j+(length/5), latch); }else{ task=new MyThread(arr, j, length, latch); } new Thread(task).start(); } latch.await(); System.out.println(total); } private class MyThread implements Runnable{ int[] arr; int startIndex; int endIndex; CountDownLatch latch; public MyThread(int[] arr,int startIndex,int endIndex,CountDownLatch latch){ this.arr=arr; this.startIndex=startIndex; this.endIndex=endIndex; this.latch=latch; } @Override public void run() { int sum=0; for(int i=startIndex;i<endIndex;i++){ sum+=arr[i]; } synchronized (MyThread.class) { total+=sum; } System.out.println(Thread.currentThread().getName()); latch.countDown(); } } }
對於CountDownLatch不熟悉的可以搜索下用法。
方式三:
通過java工具類 CyclicBarrier實現並發計算。
package test; import java.util.concurrent.BrokenBarrierException; import java.util.concurrent.CyclicBarrier; public class FiveThreadCount1 { private int[] arr={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}; private int total=0; public void test() throws InterruptedException, BrokenBarrierException{ int length=arr.length; CyclicBarrier barrier=new CyclicBarrier((length%5==0?5:6)+1); System.out.println(length); for(int j=0;j<length;j+=(length/5)){ MyThread task; if( (j+(length/5))<=length){ task=new MyThread(arr, j, j+(length/5), barrier); }else{ task=new MyThread(arr, j, length, barrier); } new Thread(task).start(); } barrier.await(); System.out.println(total); } private class MyThread implements Runnable{ int[] arr; int startIndex; int endIndex; CyclicBarrier barrier; public MyThread(int[] arr,int startIndex,int endIndex,CyclicBarrier barrier){ this.arr=arr; this.startIndex=startIndex; this.endIndex=endIndex; this.barrier=barrier; } @Override public void run() { int sum=0; for(int i=startIndex;i<endIndex;i++){ sum+=arr[i]; } synchronized (MyThread.class) { total+=sum; } try { System.out.println(Thread.currentThread().getName()); barrier.await(); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (BrokenBarrierException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
總結
總體來說,代碼二的方式二、三,效率會高一點。以上代碼都是通過main方法調用示例代碼的test方法,輸出結果到控制臺。
到此這篇關於Java使用5個線程計算數組之和的文章就介紹到這瞭,更多相關Java 線程數組之和內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- 詳解Java停止線程的四種方法
- 多線程Thread,Runnable,Callable實現方式
- java多線程CyclicBarrier的使用案例,讓線程起步走
- java中線程池最實用的創建與關閉指南
- Java基礎之多線程的三種實現方式