1. 程式人生 > >作業系統實驗——序列、多執行緒和執行緒池三種方式計算矩陣乘法

作業系統實驗——序列、多執行緒和執行緒池三種方式計算矩陣乘法

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];         
			}
		}
	}

}
驅動類Driver:
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.執行結果: