簡體   English   中英

Java中的多線程矩陣乘法

[英]Multithreading matrix multiplication in Java

我正在嘗試使用* d個線程(用於打印完成矩陣中一個索引的總和)構建一個用於乘以兩個矩陣(A [a,b],B [c,d])的程序,為此,我使用了一個'monitor'類,它將用作控制器來實現線程之間的同步,'multiplier'類用來表示單個線程和一個主程序類。 我的想法是線程將進行計算,當線程(0,0)將打印他的總和時,他將發出下一個信號。 由於某種原因,在打印第一個索引后 - 所有線程都處於等待模式並且不會測試我的狀況。 你能看看我的代碼並告訴我我的錯誤在哪里嗎?

監控類:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

final class Monitor {
    private Lock lock;
    int index;
    Condition cond; 
    public Monitor () {
        lock = new ReentrantLock();
        cond = lock.newCondition();
        this.index = 0;
    }

    public synchronized void finished(int x, double sum) throws InterruptedException {
        lock.lock();
        if(index != x) {
            while(index != x) cond.await();
            System.out.printf("%9.2f ",sum);
            index++;
            lock.unlock();
            cond.signalAll();
          }
        else {
            System.out.printf("%9.2f ",sum);
            index++;
            try { lock.unlock(); }
            catch (java.lang.IllegalMonitorStateException e) {};
            try { lock.unlock(); }
            catch (java.lang.IllegalMonitorStateException e) {};
        }
        if(index % 5 == 0) System.out.println();
    }
}

乘數:

public class Multiplier extends Thread {
    private int index;
    private double [] vectorOne;
    private double [] vectorTwo;
    private Monitor monitor;
    private double sum;

    //constructor
    public Multiplier(int index, Monitor monitor,double [] vectorOne,double [] vectorTwo) {
        this.index = index;
        this.monitor = monitor;
        this.vectorOne = vectorOne;
        this.vectorTwo = vectorTwo;
    }

    public void VecMulti() {
        sum = 0;
        for (int i = 0 ; i < vectorOne.length ; i++) 
            sum += vectorOne[i] * vectorTwo[i];
    }

    public double getSum() {
        return sum;
    }

    public void run() {
        VecMulti();
        try {
            monitor.finished(index, sum);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

主要課程:

public class MatrixMultiTest {
    public static void main(String[] args) {
        Monitor monitor = new Monitor(3*5);
        Matrix A = Matrix.random(3,4);
        Matrix B = Matrix.random(4,5);
        System.out.println("Matrix No1");
        A.show();
        System.out.println();
        System.out.println("Matrix No2");
        B.show();
        System.out.println();
        System.out.println("Multi Matrix");

        for (int i = 0; i < 3; i++)
            for (int j = 0; j < 5; j++) {
                Multiplier myThr = new Multiplier(i*5+j,
                        monitor,A.getRow(i),B.getCol(j));
                myThr.start();
                try {
                    myThr.join();
                } catch (InterruptedException e) {
                //  TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
    }
}

finished()方法充滿了問題:

  • 第一個問題是synchronized關鍵字。 它必須被刪除。 使用此關鍵字,如果第一個進入的線程具有非零索引,程序將死鎖 - 線程將永遠停在等待條件發出信號,這將永遠不會到來,因為沒有其他線程可以進入finished()方法。

  • 第二個錯誤在於else塊:

else {
    System.out.printf("%9.2f ",sum);
    index++;
    try { lock.unlock(); }
    catch (java.lang.IllegalMonitorStateException e) {};
    try { lock.unlock(); }
    catch (java.lang.IllegalMonitorStateException e) {};
}

它永遠不會調用cond.signalAll() ,所以在index=0的線程通過后,其他線程將永遠停留。

  • 第三個問題是if(index != x) {.. block, cond.signalAll()lock.unlock()順序錯誤:
lock.unlock();
cond.signalAll();

ConditionsignalAll()方法文檔說明:

當調用此方法時,實現可能(並且通常確實)要求當前線程保持與此Condition關聯的鎖。 實現必須記錄此前提條件以及未保持鎖定時所采取的任何操作。 通常,將拋出異常,例如IllegalMonitorStateException

必須按順序切換這兩行代碼,否則將拋出IllegalMonitorStateException

該方法的工作版本可能如下所示:

public void finished(int x, double sum) throws InterruptedException {
    try {
        lock.lock();
        while (index != x) {
            cond.await();
        }
        System.out.printf("%9.2f ", sum);
        index++;
        cond.signalAll();
    } finally {
        lock.unlock();
    }
    if (index % 5 == 0) System.out.println();
}

有趣的是,OP提供的代碼實際上甚至可以解決所有這些錯誤,但僅僅是由於MatrixMultiTest類中的MatrixMultiTest代碼:

try {
    myThr.join();
} catch (InterruptedException e) {
//  TODO Auto-generated catch block
    e.printStackTrace();
}

每個線程都被創建,然后按順序啟動和連接,因此只有一個線程在任何時刻都嘗試獲取synchronized synchronized finished()方法的隱式鎖,並且i*5+j索引值確保線程獲取此隱式按index順序鎖定:0,1,2等。這意味着在方法內部, index始終等於x ,並且每個線程都通過finished() else塊,允許程序完成執行。 cond.await()實際上從未被調用過。

如果刪除了join塊,則可能會打印某些值,但程序最終會死鎖。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM