作業系統實驗——序列、多執行緒和執行緒池三種方式計算矩陣乘法
阿新 • • 發佈:2019-01-06
驅動類Driver:package cn.edu.seu.yujun.OS; /** * * @author Fish * Date:2015/4/7 */ public class WorkThread implements Runnable { private int start;//計算開始位置,以此區分工作執行緒工作任務 private int [][]A; private int [][]B; private int [][]C; //工作執行緒構造方法 public WorkThread(int start,int [][]A,int [][]B,int [][]C){ this.start=start; this.A=A; this.B=B; this.C=C; } @Override public void run() { int i,j,k; //根據執行緒數量劃分每個工作執行緒任務 for(i=start; i<Driver.M; i +=Driver.NUM_THREADS) { for(j=0;j<Driver.N;j++) { for( k=0; k< Driver.K;k++) C[i][j]+=A[i][k]*B[k][j]; } } } }
package cn.edu.seu.yujun.OS; /** * @author Fish * Date:2015/4/7 */ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class Driver { public final static int M=1024;//定義常量:矩陣A的行數 public final static int K=1024;//定義常量:矩陣A的列數,矩陣B的行數 public final static int N=1024;//定義常量:矩陣B的列數 final static int NUM_THREADS=2;//定義常量:執行緒數量 private static int [][]A;//矩陣A private static int [][]B;//矩陣B private static int [][]C;//矩陣C //--------------------- //驅動類構造方法 public Driver(){ A=new int[M][K]; B=new int[K][N]; C=new int[M][N];//A、B、C初始化 fillRandom(A);//用0-99的隨機數初始化矩陣A fillRandom(B);//用0-99的隨機數初始化矩陣B for(int i=0;i<M;i++) for(int j=0;j<N;j++) C[i][j]=0;//將C矩陣全置零 } //------------------- //初始化方法:產生0-99的隨機數初始化矩陣A、B private void fillRandom(int[][] A) { for(int i=0;i<A.length;i++){ for(int j=0;j<A[i].length;j++) A[i][j]=(int)(Math.random()*100); } } //-------------------- //序列矩陣乘法運算 public static void singleThread(){ for(int i=0;i<M;i++){ for(int j=0;j<N;j++){ for(int k=0;k<K;k++) C[i][j]+=A[i][k]*B[k][j]; } } } //---------------------- //main函式 public static void main(String[] args){ new Driver();//新建一個驅動類物件 //隨機產生三組C矩陣位置資訊,便於後面驗證三種方法計算結果是否都正確 int []rol=new int[3]; int []col=new int[3]; for(int i=0;i<rol.length;i++){ rol[i]=(int)(Math.random()*M); col[i]=(int)(Math.random()*N); } //-------------------------------- //並行(4執行緒)方法:建立四個工作執行緒,每個執行緒完成矩陣乘法運算的1/4工作 Thread[] workers=new Thread[NUM_THREADS]; for(int i=0;i<NUM_THREADS;i++) workers[i]=new Thread(new WorkThread(i,A,B,C));//建立四個工作執行緒 long time1= System.currentTimeMillis();//記錄開始時間 for(int i=0;i<NUM_THREADS;i++){ workers[i].start();//啟動四個工作執行緒 } for(int i=0;i<NUM_THREADS;i++){ try{ workers[i].join();//等待當前執行緒執行結束 }catch(InterruptedException e){ e.printStackTrace(); } } long time2=System.currentTimeMillis();//記錄結束時間 //列印方法一使用的時間和矩陣C三個隨機位置的值 System.out.println("計算["+M+","+K+"]與["+K+","+N+"]階矩陣乘法,並行("+NUM_THREADS+"執行緒)用時:"+(time2-time1)+"毫秒"); System.out.println(C[rol[0]][col[0]]+" "+C[rol[1]][col[1]]+" "+C[rol[2]][col[2]]); System.out.println(); //--------------------------------- //方法二:序列也就是直接進行運算 for(int i=0;i<M;i++) for(int j=0;j<N;j++) C[i][j]=0;//將C矩陣全置零 long time3=System.currentTimeMillis();//記錄開始時間 singleThread();//呼叫序列計算函式 long time4=System.currentTimeMillis();//記錄結束時間 //列印方法二使用的時間和矩陣C三個隨機位置的值 System.out.println("計算["+M+","+K+"]與["+K+","+N+"]階矩陣乘法,直接計算用時:"+(time4-time3)+"毫秒"); System.out.println(C[rol[0]][col[0]]+" "+C[rol[1]][col[1]]+" "+C[rol[2]][col[2]]); System.out.println(); //------------------------------ //方法三:使用執行緒池方法進行運算 for(int i=0;i<M;i++) for(int j=0;j<N;j++) C[i][j]=0;//將C矩陣全置零 //建立四個工作執行緒 Thread []poolThreads=new Thread[NUM_THREADS]; for(int i=0;i<NUM_THREADS;i++) poolThreads[i]=new Thread(new WorkThread(i,A,B,C)); //建立執行緒池 ExecutorService pool = Executors.newCachedThreadPool(); long time5=System.currentTimeMillis();//記錄開始時間 for(int i=0;i<NUM_THREADS;i++) pool.execute(poolThreads[i]);//將四個工作執行緒放入執行緒池中執行 pool.shutdown();//線上程池終止前允許執行以前提交的任務 while (true) { if (pool.isTerminated()) { break; } }//用一個死迴圈判斷執行緒池是否執行完成 long time6=System.currentTimeMillis();//記錄結束時間 //列印方法二使用的時間和矩陣C三個隨機位置的值 System.out.println("計算["+M+","+K+"]與["+K+","+N+"]階矩陣乘法,執行緒池計算用時:"+(time6-time5)+"毫秒"); System.out.println(C[rol[0]][col[0]]+" "+C[rol[1]][col[1]]+" "+C[rol[2]][col[2]]); } }
5.執行結果: