Java中的多线程矩阵乘法
我试图构建一个程序,使用a*d线程(用于打印完成的矩阵中一个索引的总和)乘以两个矩阵(a[a,b],b[c,d]),为此,我使用了一个“monitor”类,该类将用作控制器来同步线程之间的大小,“乘法器”类表示单个线程和主程序类。我的想法是线程将进行计算,当线程(0,0)将打印其总和时,他将向下一行发出信号。出于某种原因,在打印第一个索引后,所有线程都处于等待模式,不会测试我的状态。你能看一下我的密码,告诉我哪里错了吗 监控类:Java中的多线程矩阵乘法,java,multithreading,matrix,conditional,wait,Java,Multithreading,Matrix,Conditional,Wait,我试图构建一个程序,使用a*d线程(用于打印完成的矩阵中一个索引的总和)乘以两个矩阵(a[a,b],b[c,d]),为此,我使用了一个“monitor”类,该类将用作控制器来同步线程之间的大小,“乘法器”类表示单个线程和主程序类。我的想法是线程将进行计算,当线程(0,0)将打印其总和时,他将向下一行发出信号。出于某种原因,在打印第一个索引后,所有线程都处于等待模式,不会测试我的状态。你能看一下我的密码,告诉我哪里错了吗 监控类: import java.util.concurrent.locks
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();
}
}
}
公共类乘数扩展线程{
私有整数索引;
专用双[]矢量;
私人双【】vectorTwo;
私人监听;
私人双和;
//建造师
公共乘数(整数索引、监视器监视器、双[]向量一、双[]向量二){
这个指数=指数;
this.monitor=监视器;
this.vectorOne=vectorOne;
this.vectorwo=vectorwo;
}
公共空间{
总和=0;
for(int i=0;i
主要类别:
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();
}
}
}
}
公共类矩阵多重测试{
公共静态void main(字符串[]args){
监视器=新监视器(3*5);
矩阵A=矩阵随机(3,4);
矩阵B=矩阵随机(4,5);
系统输出打印项次(“矩阵1”);
A.show();
System.out.println();
系统输出打印项次(“矩阵No2”);
B.show();
System.out.println();
System.out.println(“多矩阵”);
对于(int i=0;i<3;i++)
对于(int j=0;j<5;j++){
乘数MyTR=新的乘数(i*5+j,
监视器,A.getRow(i),B.getCol(j));
mytr.start();
试一试{
mytr.join();
}捕捉(中断异常e){
//TODO自动生成的捕捉块
e、 printStackTrace();
}
}
}
}
这个finished()
方法充满了问题:
- 第一个问题是
关键字。它必须被移除。使用此关键字,如果第一个进入的线程具有非零索引,则程序将死锁-线程将永远停在等待条件发出信号的位置,这将永远不会出现,因为没有其他线程可以进入synchronized
方法finished()
- 第二个故障与
块有关:else
cond.signalAll()
,因此在index=0
的线程通过后,其他线程将永远停驻
- 第三个问题是,在
块中,if(index!=x){..
和cond.signalAll()
的顺序错误:lock.unlock()
条件
的signalAll()
方法声明:
调用此方法时,实现可能(通常确实)要求当前线程持有与此条件关联的锁。实现必须记录此前提条件以及未持有锁时所采取的任何操作。通常会引发异常,如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
类中的这段代码:
try {
myThr.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
每个线程都被创建,然后按顺序启动和连接,因此只有一个线程试图获取synchronizedfinished()上的隐式锁
方法在任何时刻,并且i*5+j
索引值确保线程按照其索引的顺序获取此隐式锁:0、1、2等。这意味着在方法中,索引始终等于x
,并且每个线程都在完成()
,允许程序完成执行。cond.await()
实际上从未被调用
如果删除了join
块,则可能会打印一些值,但程序最终会死锁。while(index!=x)
将永远不会停止,因为方法参数x和索引将永远不会更改,您需要检查所有线程共享的变量,并且java在这里是按值复制的。@zapl不是“monitor”上的索引可以被视为与所有线程共享的值吗?每当线程运行“finished”时,它都会更改。哦,ups,索引
是索引我创建了一个共享变量。我要尝试新的乘数(i*5+j..
就其中一个而言,否则你的索引会被打个赌:如果你将多线程解决方案与简单的单线程解决方案进行基准测试,你的解决方案会慢得多…至少在10*10左右的维度上,因为你会给操作带来巨大的开销。@RalfKleberhoff可能,但这不是重点。我不是g为提高这项任务的效率而努力。
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();
}
try {
myThr.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}