繁体   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