Умножение матриц с потоками Java
Я пытаюсь создать программу на Java с потоками для умножения матриц. Это исходный код:
import java.util.Random;
public class MatrixTest {
//Creating the matrix
static int[][] mat = new int[3][3];
static int[][] mat2 = new int[3][3];
static int[][] result = new int[3][3];
public static void main(String [] args){
//Creating the object of random class
Random rand = new Random();
//Filling first matrix with random values
for (int i = 0; i < mat.length; i++) {
for (int j = 0; j < mat[i].length; j++) {
mat[i][j]=rand.nextInt(10);
}
}
//Filling second matrix with random values
for (int i = 0; i < mat2.length; i++) {
for (int j = 0; j < mat2[i].length; j++) {
mat2[i][j]=rand.nextInt(10);
}
}
try{
//Object of multiply Class
Multiply multiply = new Multiply(3,3);
//Threads
MatrixMultiplier thread1 = new MatrixMultiplier(multiply);
MatrixMultiplier thread2 = new MatrixMultiplier(multiply);
MatrixMultiplier thread3 = new MatrixMultiplier(multiply);
//Implementing threads
Thread th1 = new Thread(thread1);
Thread th2 = new Thread(thread2);
Thread th3 = new Thread(thread3);
//Starting threads
th1.start();
th2.start();
th3.start();
th1.join();
th2.join();
th3.join();
}catch (Exception e) {
e.printStackTrace();
}
//Printing the result
System.out.println("\n\nResult:");
for (int i = 0; i < result.length; i++) {
for (int j = 0; j < result[i].length; j++) {
System.out.print(result[i][j]+" ");
}
System.out.println();
}
}//End main
}//End Class
//Multiply Class
class Multiply extends MatrixTest {
private int i;
private int j;
private int chance;
public Multiply(int i, int j){
this.i=i;
this.j=j;
chance=0;
}
//Matrix Multiplication Function
public synchronized void multiplyMatrix(){
int sum=0;
int a=0;
for(a=0;a<i;a++){
sum=0;
for(int b=0;b<j;b++){
sum=sum+mat[chance][b]*mat2[b][a];
}
result[chance][a]=sum;
}
if(chance>=i)
return;
chance++;
}
}//End multiply class
//Thread Class
class MatrixMultiplier implements Runnable {
private final Multiply mul;
public MatrixMultiplier(Multiply mul){
this.mul=mul;
}
@Override
public void run() {
mul.multiplyMatrix();
}
}
Я только что попробовал Eclipse, и он работает, но теперь я хочу создать другую версию этой программы, в которой я использую один поток для каждой ячейки, которую я буду иметь в матрице результатов. Например, у меня есть две матрицы 3х3. Таким образом, матрица результата будет 3х3. Затем я хочу использовать 9 потоков для вычисления каждой из 9 ячеек матрицы результатов.
Может кто-нибудь мне помочь?
С уважением
5 ответов
С этим кодом я думаю, что я решаю свою проблему. Я не использую синхронизированный в методах, но я думаю, что в этом нет необходимости.
import java.util.Scanner;
class MatrixProduct extends Thread {
private int[][] A;
private int[][] B;
private int[][] C;
private int rig,col;
private int dim;
public MatrixProduct(int[][] A,int[][] B,int[][] C,int rig, int col,int dim_com)
{
this.A=A;
this.B=B;
this.C=C;
this.rig=rig;
this.col=col;
this.dim=dim_com;
}
public void run()
{
for(int i=0;i<dim;i++){
C[rig][col]+=A[rig][i]*B[i][col];
}
System.out.println("Thread "+rig+","+col+" complete.");
}
}
public class MatrixMultiplication {
public static void main(String[] args)
{
Scanner In=new Scanner(System.in);
System.out.print("Row of Matrix A: ");
int rA=In.nextInt();
System.out.print("Column of Matrix A: ");
int cA=In.nextInt();
System.out.print("Row of Matrix B: ");
int rB=In.nextInt();
System.out.print("Column of Matrix B: ");
int cB=In.nextInt();
System.out.println();
if(cA!=rB)
{
System.out.println("We can't do the matrix product!");
System.exit(-1);
}
System.out.println("The matrix result from product will be "+rA+" x "+cB);
System.out.println();
int[][] A=new int[rA][cA];
int[][] B=new int[rB][cB];
int[][] C=new int[rA][cB];
MatrixProduct[][] thrd= new MatrixProduct[rA][cB];
System.out.println("Insert A:");
System.out.println();
for(int i=0;i<rA;i++)
{
for(int j=0;j<cA;j++)
{
System.out.print(i+","+j+" = ");
A[i][j]=In.nextInt();
}
}
System.out.println();
System.out.println("Insert B:");
System.out.println();
for(int i=0;i<rB;i++)
{
for(int j=0;j<cB;j++)
{
System.out.print(i+","+j+" = ");
B[i][j]=In.nextInt();
}
}
System.out.println();
for(int i=0;i<rA;i++)
{
for(int j=0;j<cB;j++)
{
thrd[i][j]=new MatrixProduct(A,B,C,i,j,cA);
thrd[i][j].start();
}
}
for(int i=0;i<rA;i++)
{
for(int j=0;j<cB;j++)
{
try{
thrd[i][j].join();
}
catch(InterruptedException e){}
}
}
System.out.println();
System.out.println("Result");
System.out.println();
for(int i=0;i<rA;i++)
{
for(int j=0;j<cB;j++)
{
System.out.print(C[i][j]+" ");
}
System.out.println();
}
}
}
Вы можете создать n
Темы следующим образом (Примечание: numberOfThreads
количество потоков, которые вы хотите создать. Это будет количество ячеек):
List<Thread> threads = new ArrayList<>(numberOfThreads);
for (int x = 0; x < numberOfThreads; x++) {
Thread t = new Thread(new MatrixMultiplier(multiply));
t.start();
threads.add(t);
}
for (Thread t : threads) {
t.join();
}
Пожалуйста, используйте новую среду Executor для создания потоков, вместо того, чтобы вручную выполнять сантехнику.
ExecutorService executor = Executors.newFixedThreadPool(numberOfThreadsInPool);
for (int i = 0; i < numberOfThreads; i++) {
Runnable worker = new Thread(new MatrixMultiplier(multiply));;
executor.execute(worker);
}
executor.shutdown();
while (!executor.isTerminated()) {
}
Рассмотрим Matrix.java и Main.java следующим образом.
public class Matrix extends Thread {
private static int[][] a;
private static int[][] b;
private static int[][] c;
/* You might need other variables as well */
private int i;
private int j;
private int z1;
private int s;
private int k;
public Matrix(int[][] A, final int[][] B, final int[][] C, int i, int j, int z1) { // need to change this, might
// need some information
a = A;
b = B;
c = C;
this.i = i;
this.j = j;
this.z1 = z1; // a[0].length
}
public void run() {
synchronized (c) {
// 3. How to allocate work for each thread (recall it is the run function which
// all the threads execute)
// Here this code implements the allocated work for perticular thread
// Each element of the resulting matrix will generate by a perticular thread
for (s = 0, k = 0; k < z1; k++)
s += a[i][k] * b[k][j];
c[i][j] = s;
}
}
public static int[][] returnC() {
return c;
}
public static int[][] multiply(final int[][] a, final int[][] b) {
/*
* check if multipication can be done, if not return null allocate required
* memory return a * b
*/
final int x = a.length;
final int y = b[0].length;
final int z1 = a[0].length;
final int z2 = b.length;
if (z1 != z2) {
System.out.println("Cannnot multiply");
return null;
}
final int[][] c = new int[x][y];
int i, j;
// 1. How to use threads to parallelize the operation?
// Every element in the resulting matrix will be determined by a different
// thread
// 2. How may threads to use?
// x * y threads are used to generate the result.
for (i = 0; i < x; i++)
for (j = 0; j < y; j++) {
try {
Matrix temp_thread = new Matrix(a, b, c, i, j, z1);
temp_thread.start();
// 4. How to synchronize?
// synchronized() is used with join() to guarantee that the perticular thread
// will be accessed first
temp_thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return Matrix.returnC();
}
}
Ты можешь использовать Main.java
чтобы получить 2 матрицы, которые нужно перемножить.
class Main {
public static int [][] a = {{1, 1, 1},
{1, 1, 1},
{1, 1, 1}};
public static int [][] b = {{1 },
{1 },
{1 }};
public static void print_matrix(int [][] a) {
for(int i=0; i < a.length; i++) {
for(int j=0; j< a[i].length; j++)
System.out.print(a[i][j] + " ");
System.out.println();
}
}
public static void main(String [] args) {
int [][] x = Matrix.multiply(a, b);
print_matrix(x); // see if the multipication is correct
}
}
Проще говоря, все, что вам нужно сделать, это
1) Создайте n (без ячеек в результирующей матрице) потоков. Назначьте их роли. (Пример: Рассмотрим M X N, где M и N - матрицы. 'Thread1' отвечает за умножение элементов row_1 M на элементы column_1 N и сохранение результата. Это значение для ячейки результирующей матрицы cell_1.)
2) Запустите процесс каждого потока. (методом start())
3) Дождитесь, пока все потоки не завершат свои процессы, и сохраните результирующее значение каждой ячейки. Потому что эти процессы должны быть завершены до отображения результирующей матрицы. (Вы можете сделать это с помощью методов join() и других возможностей)
4) Теперь вы можете отобразить результирующую матрицу.
Замечания:
1) Поскольку в этом примере общие ресурсы (M и N) используются только для целей только для чтения, вам не нужно использовать "синхронизированные" методы для доступа к ним.
2) Вы можете видеть, что в этой программе есть группа запущенных потоков, и все они должны самостоятельно достичь определенного статуса, прежде чем продолжить следующий шаг всей программы. Эта многопоточная модель программирования называется Барьером.
Попробовал ниже код в затмении в соответствии с потоком для каждой ячейки. Работает нормально, можете проверить.
class ResMatrix{
static int[][] arrres = new int[2][2];
}
class Matrix{
int [][] arr = new int[2][2];
void setV(int v) {
//int tmp = v;
for(int i=0;i<2;i++) {
for(int j=0;j<2;j++) {
arr[i][j] = v;
v = v + 1;
}
}
}
int [][] getV(){
return arr;
}
}
class Mul extends Thread {
public int row;
public int col;
Matrix m;
Matrix m1;
Mul(int row,int col,Matrix m,Matrix m1){
this.row = row;
this.col = col;
this.m = m;
this.m1 = m1;
}
public void run() {
//System.out.println("Started Thread: "+Thread.currentThread().getName());
int tmp=0;
for(int i=0;i<2;i++) {
tmp = tmp + this.m.getV()[row][i] * this.m1.getV()[i][col];
}
ResMatrix.arrres[row][col] = tmp;
System.out.println("Started Thread END: "+Thread.currentThread().getName());
}
}
public class Test {
//static int[][] arrres =new int[2][2];
public static void main(String[]args) throws InterruptedException {
Matrix mm = new Matrix();
mm.setV(1);
Matrix mm1 = new Matrix();
mm1.setV(2);
for(int i=0;i<2;i++) {
for(int j=0;j<2;j++) {
Mul mul = new Mul(i,j,mm,mm1);
mul.start();
// mul.join();
}
}
for(int i=0;i<2;i++) {
for(int j=0;j<2;j++) {
System.out.println("VALUE: "+ResMatrix.arrres[i][j]);
}
}
}
}
В своем решении я назначил каждому работнику ряд строк numRowForThread
равно: (количество строк в matA)/(количество потоков).
public class MatMulConcur {
private final static int NUM_OF_THREAD =1 ;
private static Mat matC;
public static Mat matmul(Mat matA, Mat matB) {
matC = new Mat(matA.getNRows(),matB.getNColumns());
return mul(matA,matB);
}
private static Mat mul(Mat matA,Mat matB) {
int numRowForThread;
int numRowA = matA.getNRows();
int startRow = 0;
Worker[] myWorker = new Worker[NUM_OF_THREAD];
for (int j = 0; j < NUM_OF_THREAD; j++) {
if (j<NUM_OF_THREAD-1){
numRowForThread = (numRowA / NUM_OF_THREAD);
} else {
numRowForThread = (numRowA / NUM_OF_THREAD) + (numRowA % NUM_OF_THREAD);
}
myWorker[j] = new Worker(startRow, startRow+numRowForThread,matA,matB);
myWorker[j].start();
startRow += numRowForThread;
}
for (Worker worker : myWorker) {
try {
worker.join();
} catch (InterruptedException e) {
}
}
return matC;
}
private static class Worker extends Thread {
private int startRow, stopRow;
private Mat matA, matB;
public Worker(int startRow, int stopRow, Mat matA, Mat matB) {
super();
this.startRow = startRow;
this.stopRow = stopRow;
this.matA = matA;
this.matB = matB;
}
@Override
public void run() {
for (int i = startRow; i < stopRow; i++) {
for (int j = 0; j < matB.getNColumns(); j++) {
double sum = 0;
for (int k = 0; k < matA.getNColumns(); k++) {
sum += matA.get(i, k) * matB.get(k, j);
}
matC.set(i, j, sum);
}
}
}
}
где для class Mat
Я использовал эту реализацию:
public class Mat {
private double[][] mat;
public Mat(int n, int m) {
mat = new double[n][m];
}
public void set(int i, int j, double v) {
mat[i][j] = v;
}
public double get(int i, int j) {
return mat[i][j];
}
public int getNRows() {
return mat.length;
}
public int getNColumns() {
return mat[0].length;
}
}