我整晚都在研究这个问题并且没有找到解决方案,所以如果有人能帮助我,我真的很感激!我可能错过了一些非常明显的东西。这是一个理解同步的赋值,我们在前面的赋值中使用线程来乘以2个矩阵。在前面的赋值中,每个线程乘以一行,因此线程数与行数一样多。
在这个赋值中,我们只应该使用5个线程 - 所有线程都应该以一行/一列开始,一旦线程完成,它应该使用同步选择下一个可用的行/列,所以现在两个线程将结束做同一列。
This question帮助我找到了正确的方向,但我必须对实施做错事,因为到目前为止,我只是将程序运用到:
这是我的主要课程和一些辅助方法:
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Random;
import java.util.Scanner;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Lock;
public class MatrixMult {
public static void main(String[] args){
int[][] matrixA;
int[][] matrixB;
int colA = 0;
int rowA = 0;
int colB = 0;
int rowB = 0;
Scanner userInput = new Scanner( System.in );
System.out.println("Please enter the dimensions of matrix A");
do{
System.out.print("column for matrix A: ");
colA = userInput.nextInt();
System.out.println();
} while(!validDimension(colA));
rowB = colA;
do{
System.out.print("row for matrix A: ");
rowA = userInput.nextInt();
System.out.println();
} while(!validDimension(rowA));
matrixA = new int[rowA][colA];
System.out.println("Please enter the dimensions of matrix B:");
do{
System.out.print("column for matrix B: ");
colB = userInput.nextInt();
System.out.println();
} while(!validDimension(colB));
matrixB = new int[rowB][colB];
fillMatrix(matrixA);
fillMatrix(matrixB);
System.out.println("Would you like to print out matrix A and B? (y/n)");
String userResponse = userInput.next();
if(userResponse.equalsIgnoreCase("y")){
System.out.println("Matrix A:");
printBackMatrix(matrixA);
System.out.println();
System.out.println("Matrix B:");
printBackMatrix(matrixB);
System.out.println();
}
int[][] matrixProduct3 = multMatrixWithThreadsSync(matrixA, matrixB);
String fileName = "C:/matrix.txt";
System.out.println("Matrix product is being written to "+fileName);
try {
printMatrixToFile(matrixProduct3, fileName);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static int[][] multMatrixWithThreadsSync(int[][] matrixA, int[][] matrixB) {
int[][] matrixProduct = new int[matrixA.length][matrixB[0].length];
int[] matrixProductColumn = new int[matrixA.length];
Runnable task = new MultMatrixByRow(matrixA, matrixB, matrixProduct);
for(int i=0; i<5; i++){
Thread worker = new Thread(task);
worker.start();
// System.out.println(worker.getName());
try {
worker.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return matrixProduct;
}
private static void printMatrixToFile(int[][] matrix, String fileName) throws IOException{
PrintWriter userOutput = new PrintWriter(new FileWriter(fileName));
for(int i=0; i<matrix.length; i++){
for(int j=0; j<matrix[0].length; j++){
userOutput.print(matrix[i][j]+" ");
}
userOutput.println();
}
userOutput.close();
}
private static void printBackMatrix(int[][] matrix) {
for(int i=0; i<matrix.length; i++){
for(int j=0; j<matrix[0].length; j++){
System.out.print(matrix[i][j]+" ");
}
System.out.println();
}
}
private static void fillMatrix(int[][] matrix) {
Random rand = new Random();
for(int i=0; i<matrix.length; i++){
for(int j=0; j<matrix[0].length; j++){
matrix[i][j] = rand.nextInt(100) + 1;
}
}
}
public static boolean validDimension(int dim){
if (dim <= 0 || dim >1000){
System.err.println("Dimension value entered is not valid");
return false;
}
return true;
}
}
这是我的runnable类:
public class MultMatrixByRow implements Runnable {
private int i;
private int[][] matrixA;
private int[][] matrixB;
private int[][] matrixProduct;
public MultMatrixByRow(int[][] A, int[][] B, int[][] C) {
this.matrixA = A;
this.matrixB = B;
this.matrixProduct = C;
}
@Override
public void run(){
// while(i < matrixProduct.length){
int rowToWork = 0;
synchronized (this){
// System.out.println("i is "+i);
if ( i < matrixProduct.length){
rowToWork = i;
i++;
}
else{
return;
}
}
for(int j = 0; j < matrixB[0].length; j++){
for(int k=0; k < matrixA[0].length; k++){
matrixProduct[rowToWork][j] += matrixA[rowToWork][k]*matrixB[k][j];
}
}
// }
}
}
再次 - 真的很感激任何帮助!非常感谢。
答案 0 :(得分:3)
另外,我不太确定你的Threads应该单独解决什么,我认为它们都可以解决整个产品矩阵。您需要共享一个用于标识已处理行的变量,您可以访问这些行。
我可以修复你的代码,但我很感激你自己做这项工作,因为理解线程并发是一项任务。
编辑:同步说明:
Synchronized将一个对象作为一个锁,只有一个线程可以为它保存监视器。当有监视器用于锁定时,线程可以处理该块,如果没有,他必须等待获取监视器。
在您的情况下,您可以使用private static final Object lock = new Object();
作为锁定,您将同步
编辑2:我完全构建了你的代码
我没有为完成你的所有工作感到骄傲,但无所谓,这就是它。
package anything.synchronize_stackoverflow_post;
/**
* @date 21.11.2012
* @author Thomas Jahoda
*/
public class ConcurrentMatrixMultiplyingTask implements Runnable {
private int[][] matrixA;
private int[][] matrixB;
private int[][] matrixProduct;
//
private final ConcurrencyContext context;
public ConcurrentMatrixMultiplyingTask(ConcurrencyContext context, int[][] A, int[][] B, int[][] C) {
if (context == null) {
throw new IllegalArgumentException("context can not be null");
}
this.context = context;
this.matrixA = A;
this.matrixB = B;
this.matrixProduct = C;
}
@Override
public void run() {
while (true) {
int row;
synchronized (context) {
if (context.isFullyProcessed()) {
break;
}
row = context.nextRowNum();
}
System.out.println(Thread.currentThread().getName() + " is going to process row " + row);
// i'm not really sure if this matrix algorithm here is right, idk..
for (int j = 0; j < matrixB[0].length; j++) {
for (int k = 0; k < matrixA[0].length; k++) {
matrixProduct[row][j] += matrixA[row][k] * matrixB[k][j];
}
}
}
}
public static class ConcurrencyContext {
private final int rowCount;
private int nextRow = 0;
public ConcurrencyContext(int rowCount) {
this.rowCount = rowCount;
}
public synchronized int nextRowNum() {
if (isFullyProcessed()) {
throw new IllegalStateException("Already fully processed");
}
return nextRow++;
}
public synchronized boolean isFullyProcessed() {
return nextRow == rowCount;
}
}
}
ProcessingTask
package anything.synchronize_stackoverflow_post;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Random;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* @date 21.11.2012
* @author Thomas Jahoda
*/
public class MatrixMulti {
public static void main(String[] args) {
int[][] matrixA;
int[][] matrixB;
int colA = 0;
int rowA = 0;
int colB = 0;
int rowB = 0;
Scanner userInput = new Scanner(System.in);
System.out.println("Please enter the dimensions of matrix A");
do {
System.out.print("column for matrix A: ");
colA = userInput.nextInt();
System.out.println();
} while (!validDimension(colA));
rowB = colA;
do {
System.out.print("row for matrix A: ");
rowA = userInput.nextInt();
System.out.println();
} while (!validDimension(rowA));
matrixA = new int[rowA][colA];
System.out.println("Please enter the dimensions of matrix B:");
do {
System.out.print("column for matrix B: ");
colB = userInput.nextInt();
System.out.println();
} while (!validDimension(colB));
matrixB = new int[rowB][colB];
fillMatrix(matrixA);
fillMatrix(matrixB);
System.out.println("Would you like to print out matrix A and B? (y/n)");
String userResponse = userInput.next();
if (userResponse.equalsIgnoreCase("y")) {
System.out.println("Matrix A:");
printBackMatrix(matrixA);
System.out.println();
System.out.println("Matrix B:");
printBackMatrix(matrixB);
System.out.println();
}
int[][] matrixProduct3 = multMatrixWithThreadsSync(matrixA, matrixB);
String fileName = "test.txt";
System.out.println("Matrix product is being written to " + fileName);
try {
printMatrixToFile(matrixProduct3, fileName);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static int[][] multMatrixWithThreadsSync(int[][] matrixA, int[][] matrixB) {
int[][] matrixProduct = new int[matrixA.length][matrixB[0].length];
int[] matrixProductColumn = new int[matrixA.length];
//
ConcurrentMatrixMultiplyingTask.ConcurrencyContext context = new ConcurrentMatrixMultiplyingTask.ConcurrencyContext(matrixProduct.length);
//
Runnable task = new ConcurrentMatrixMultiplyingTask(context, matrixA, matrixB, matrixProduct);
Thread[] workers = new Thread[5];
for (int i = 0; i < workers.length; i++) {
workers[i] = new Thread(task, "Worker-"+i);
}
for (int i = 0; i < workers.length; i++) {
Thread worker = workers[i];
worker.start();
}
for (int i = 0; i < workers.length; i++) {
Thread worker = workers[i];
try {
worker.join();
} catch (InterruptedException ex) {
Logger.getLogger(MatrixMulti.class.getName()).log(Level.SEVERE, null, ex);
}
}
return matrixProduct;
}
private static void printMatrixToFile(int[][] matrix, String fileName) throws IOException {
PrintWriter userOutput = new PrintWriter(new FileWriter(fileName));
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[0].length; j++) {
userOutput.print(matrix[i][j] + " ");
}
userOutput.println();
}
userOutput.close();
}
private static void printBackMatrix(int[][] matrix) {
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[0].length; j++) {
System.out.print(matrix[i][j] + " ");
}
System.out.println();
}
}
private static void fillMatrix(int[][] matrix) {
Random rand = new Random();
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[0].length; j++) {
matrix[i][j] = rand.nextInt(100) + 1;
}
}
}
public static boolean validDimension(int dim) {
if (dim <= 0 || dim > 1000) {
System.err.println("Dimension value entered is not valid");
return false;
}
return true;
}
}
答案 1 :(得分:1)
要解决您的问题,您需要定义什么是“工作单位”。这个“工作单元”(或任务)是每个线程将要执行的。在定义之后,您可以推断出这个工作单元需要做什么工作。
在矩阵乘法的情况下,自然工作单元是所得矩阵的每个单元格。因此,给定矩阵A [i,j]和B [j,k],您的计算可以集中于每个{{1的向量A.row(x)(点)B.column(y)的点积。 }}
下一步是代表每项任务。将任务“提供”到线程的理想结构是队列。 java.util.concurrent.BlockingQueue就是这样一个例子,同步工作在幕后完成。鉴于您被要求“手动”推理同步,您可以使用另一个容器,如List(甚至是数组)。您的结构将包含定义结果矩阵的每个单元格。 可能是这样的:
(0<=x<i,0<=y<k)
现在,您需要一个给定Cell和Matrices A和B的任务,可以计算该单元格的值。这是您的工作单元,因此在线程的上下文中运行的是什么。在这里,您还需要决定是否要放置结果。在java中你可以使用future并在线程的上下文之外组装你的矩阵,但是为了简单起见,我将共享一个可以保存结果的数组。 (根据定义,不会有任何碰撞)
class Cell; // int x, int y, getters, setters, ...
// build the structure that contains the work to be shared
List<Cell> cells = new LinkedList<Cell>();
for (int i=0;i<a.rows;i++) {
for (int j=0;j<b.columns;j++) {
cells.add(new Cell(i,j)); // represent the cells of my result matrix
}
}
现在你差不多完成了。您仍然需要做的唯一事情是创建线程,使用class DotProduct implements Runnable {
int[][] a;
int[][] b;
int[][] result;
List<Cell> cells;
public DotProduct(int[][] a, int[][] b, int[][]result, List<Cell> cells) {
...
}
public void run() {
while(true) {
Cell cell = null;
synchronized(cells) { // here, we ensure exclusive access to the shared mutable structure
if (cells.isEmpty()) return; // when there're no more cells, we are done.
Cell cell = cells.get(0); // get the first cell not calculated yet
cells.remove(cell); // remove it, so nobody else will work on it
}
int x = cell.getX();
int y = cell.getY();
z = a.row(x) (dot) b.column(y);
synchronized (result) {
result[x][y] = z;
}
}
}
任务“提供它们”并等待它们完成。
请注意,我在DotProduct
上同步以更新结果矩阵。虽然根据定义,并不存在并发访问同一个单元的可能性(因为每个线程都在不同的单元上工作),但您需要通过显式同步对象来确保结果“安全地”发布到其他线程。这也可以通过声明result
result
来完成,但我不确定您是否已经覆盖了这一点。
希望这有助于理解如何处理并发问题。
答案 2 :(得分:0)
您使用所有频谱的同步原语:信号量,锁定,同步。最好从同步开始,学习东西。您实际需要的是一个资源,它指示要处理的下一行/列(如果有)。所有线程使用synchronized块访问它,读取下一行/列,将行/列移动到下一个单元格,退出块,然后处理获得的行/列。
如果满足矩阵的结束,工作线程就会退出。主线程等待所有工作线程使用Thread.join()退出。
答案 3 :(得分:0)
你真的误解了上一个问题的答案。需要在线程之间共享rowToWork
。一个线程应该在构造时调用一个方法来获取它的初始值。您需要了解您的Critical Section是给定线程的下一行的归属。