[英]Synchronized threads for multiplying matrices
我一直在研究這個問題並且沒有找到解決方案,所以如果有人能幫助我,我真的很感激! 我可能錯過了一些非常明顯的東西。 這是一個理解同步的賦值,我們在前面的賦值中使用線程來乘以2個矩陣。 在前面的賦值中,每個線程乘以一行,因此線程數與行數一樣多。
在這個賦值中,我們只應該使用5個線程 - 所有線程都應該以一行/一列開始,一旦線程完成,它應該使用同步選擇下一個可用的行/列,所以現在兩個線程將最終執行同一欄。
這個問題幫助我找到了正確的方向,但我必須對實現做錯了,因為到目前為止我只得到了以下任一項目:
這是我的主要和幾個輔助方法的類:
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];
}
}
// }
}
}
再次 - 任何幫助真的很感激! 非常感謝。
另外,我不太確定你的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;
}
}
要解決您的問題,您需要定義什么是“工作單位”。 這個“工作單元”(或任務)是每個線程將要執行的。 在定義之后,您可以推斷出這個工作單元需要做什么工作。
在矩陣乘法的情況下,自然工作單元是所得矩陣的每個單元。 因此,給定矩陣A [i,j]和B [j,k],您的計算可以集中在矢量A.row(x)(點)B.column(y)的每個點的乘積(0<=x<i,0<=y<k)
。
下一步是代表每項任務。 將任務“提供”到線程的理想結構是隊列。 java.util.concurrent.BlockingQueue就是這樣一個例子,同步工作在幕后完成。 鑒於您被要求“手動”推理同步,您可以使用另一個容器,如List(甚至是數組)。 您的結構將包含定義結果矩陣的每個單元格。 可能是這樣的:
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
}
}
現在,您需要一個給定Cell和Matrices A和B的任務,可以計算該單元格的值。 這是您的工作單元,因此在線程的上下文中運行的是什么。 在這里,您還需要決定是否要放置結果。 在java中你可以使用future並在線程的上下文之外組裝你的矩陣,但是為了簡單起見,我將共享一個可以保存結果的數組。 (根據定義,不會有任何碰撞)
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
volatile
來完成,但我不確定你是否已經覆蓋了這個基礎。
希望這有助於理解如何處理並發問題。
您使用所有頻譜的同步原語:信號量,鎖定,同步。 最好從同步開始,學習東西。 您實際需要的是一個資源,它指示要處理的下一行/列(如果有)。 所有線程使用synchronized塊訪問它,讀取下一行/列,將行/列移動到下一個單元格,退出塊,然后處理獲得的行/列。
如果滿足矩陣的結束,工作線程就會退出。 主線程等待所有工作線程使用Thread.join()退出。
你真的誤解了上一個問題的答案。 rowToWork
需要在線程之間共享。 一個線程應該在構造時調用一個方法來獲取它的初始值。 您需要了解您的關鍵部分是給定線程的下一行的歸屬。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.