Thread Pool for multiplication of arrays in java

Asked

Viewed 210 times

1

In short: How can I split matrix operations and pool threads with a fixed amount of threads using the amount of user cores? I’m cracking my head, looking at the gringo SOF, but nothing that clears my mind. I added the libraries java.util.concurrent.ExecutorService and java.util.concurrent.Executors. That’s what I’ve done so far. Main class:

public static void main(String[] args) throws IOException, InterruptedException
    {

         MatrixesManipulations matrixes = new MatrixesManipulations();


         Scanner in = new Scanner(System.in);

         System.out.print("De o valor para dimensão das duas matrizes quadradas: ");

         int n = in.nextInt();


         int[][] matrix1 = matrixes.matrixConstructor(n);
         int[][] matrix2 = matrixes.matrixConstructor(n);

         //Processadores do usuario para fazer a pool
         int cores = Runtime.getRuntime().availableProcessors();

         //Ainda não utilizado
         ExecutorService pool = Executors.newFixedThreadPool(cores);



         Thread matrix3 = new Thread(new MatrixMultiplicationThread(matrix1, matrix2, n));

         matrix3.start();
         matrix3.join();

         ////Outputs das matrizes

         matrixes.printConsole(matrix1, n, 1);

         matrixes.printConsole(matrix2, n, 2);



         matrixes.matrixesToFile(matrix1, matrix2, matrix3, n);
    }

Class MatrixManipulations:

public class MatrixesManipulations{

    public int[][] matrixConstructor(int n)
    {
        int[][] matrix = new int[n][n];

         Random rand = new Random();

         for (int i = 0 ; i < n ; i++) 
         {     
            for (int j = 0 ; j < n ; j++) 
            {
                Integer r = rand.nextInt()% 1000; 
                matrix[i][j] = Math.abs(r);
            }
         }
         return matrix;
    }

    public void printConsole(int[][] matrix, int n, int x)
    {
    synchronized (this)
        {
            if(x == 1)
            {
                System.out.println("A primeira matriz gerada de tamanho " + n + " foi:");
                for (int i = 0; i < n; i++)
                {
                    System.out.print("[");   
                    for (int j = 0; j < n; j++)
                    {
                       System.out.print(matrix[i][j] + " ");
                    }
                    System.out.println("]");
                }
                System.out.println();

            }
            if(x == 2)
            {
                System.out.println("A segunda matriz gerada de tamanho " + n + " foi:");
                for (int i = 0; i < n; i++)
                {
                    System.out.print("[");   
                    for (int j = 0; j < n; j++)
                    {
                       System.out.print(matrix[i][j] + " ");
                    }
                    System.out.println("]");
                }
                System.out.print("\n");
            }
            if(x == 3)
            {
                System.out.println("A matriz resultante gerada da multiplicação das 2 matrizes quadradas foi:");
                for (int i = 0; i < n; i++)
                {
                    System.out.print("[");   
                    for (int j = 0; j < n; j++)
                    {
                       System.out.print(matrix[i][j] + " ");
                    }
                    System.out.println("]");
                }
                System.out.print("\n");
            }
        }
    }
    public void matrixesToFile(int[][] matrix1, int[][] matrix2, int[][] matrix3, int n) throws IOException
    {
    synchronized(this)
    {
        FileWriter arqMatrix = new FileWriter("Matrizes.txt");
        PrintWriter gravarArq = new PrintWriter(arqMatrix);

        gravarArq.println("Primeira matriz gerada:");
        for (int i = 0; i < n; i++)
        {  
            gravarArq.print("[");   
            for (int j = 0; j < n; j++)
            {
                gravarArq.print(matrix1[i][j] + " ");
            }
            gravarArq.print("]\n");
        }
        gravarArq.println();

        gravarArq.println("Segunda matriz gerada:");
        for (int i = 0; i < n; i++)
        {  
            gravarArq.print("[");   
            for (int j = 0; j < n; j++)
            {
                gravarArq.print(matrix2[i][j] + " ");
            }
            gravarArq.print("]\n");
        }
        gravarArq.println();

        //int[][] matrix3 = matrixMultiplication(matrix1, matrix2, n);

        gravarArq.println("Matriz resultante da multiplicação:");
        for (int i = 0; i < n; i++)
        {  
            gravarArq.print("[");   
            for (int j = 0; j < n; j++)
            {
                gravarArq.print(matrix3[i][j] + " ");
            }
            gravarArq.print("]\n");
        }

        gravarArq.println();

        arqMatrix.close();
        System.out.println("Foi gerado um arquivo 'Matrizes.txt' no mesmo local do projeto.\n");
        }
    }

    public int[][] matrixMultiplication(int[][] matrix1, int[][] matrix2, int n)
    {
        synchronized(this)
        {
            int[][] matrix3 = new int[n][n];

            for(int i = 0 ; i < n ; i++)
            {
                for(int j = 0 ; j < n ; j++)
                {
                    for(int k = 0 ; k < n ; k++)
                    {
                        matrix3[i][j] += matrix1[i][k] * matrix2[k][j];
                    }
                }
            }
            return matrix3;
        }
    }
}

And finally, the thread:

public class MatrixMultiplicationThread implements Runnable {

    MatrixesManipulations matrixThread = new MatrixesManipulations();
    int[][] matrix1;
    int[][] matrix2;
    int n;

    public MatrixMultiplicationThread(int[][] matrix1, int[][] matrix2, int n)
    {
        this.matrix1 = matrix1;
        this.matrix2 = matrix2;
        this.n = n;
    }

    @Override
    public void run()
    {
        int[][] matrix3 = matrixThread.matrixMultiplication(matrix1, matrix2, n);
        matrixThread.printConsole(matrix3, n, 3);
    }
}

The intention is that the thread, at first, performs the operation of the matrix. But beyond that, I want it to divide for each thread to generate the user line of the outputs. Or at least (which I think is easier) that they divide and perform sum and multiplication operation, it doesn’t even have to be the pool. Another problem I’m having (which I’ll possibly also do is generating a thread) is to generate the file. Since the thread does not give a "return" but generates the matrix, I would like to know a way to pass the method public void matrixesToFile(int[][] matrix1, int[][] matrix2, int[][] matrix3, int n) throws IOException in main (which is when I use this method to unify all outputs and record in a .txt.

  • Let me get this straight, because your explanation is a little fuzzy. What you want is to run the traditional matrix multiplication algorithm in parallel and at the end save both the original and the resulting matrices to a file. That’s it?

  • That’s right! I’m sorry if I messed around a little bit, it’s just that I’m so stressed because I’ve been trying to see something for a week and I’m not getting anywhere haha

1 answer

0

Try this:

package com.example.matrixmult;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @author Victor Williams Stafusa da Silva
 */
public final class Matrix {
    private final int linhas;
    private final int colunas;
    private final double[] valores;

    public Matrix(int linhas, int colunas) {
        if (linhas <= 0 || colunas <= 0) throw new IndexOutOfBoundsException();
        this.linhas = linhas;
        this.colunas = colunas;
        this.valores = new double[linhas * colunas];
    }

    public int getLinhas() {
        return linhas;
    }

    public int getColunas() {
        return colunas;
    }

    public double get(int linha, int coluna) {
        if (linha < 0 || linha >= linhas || coluna < 0 || coluna >= colunas) throw new IndexOutOfBoundsException();
        return valores[coluna * linhas + linha];
    }

    public void set(int linha, int coluna, double valor) {
        if (linha < 0 || linha >= linhas || coluna < 0 || coluna >= colunas) throw new IndexOutOfBoundsException();
        valores[coluna * linhas + linha] = valor;
    }

    public Matrix multiply(Matrix outra) {
        if (outra == null || colunas != outra.linhas) {
            throw new IllegalArgumentException("As matrizes não têm tamanhos compatíveis para serem multiplicadas.");
        }
        var nova = new Matrix(linhas, outra.colunas);
        for (var linha = 0; linha < linhas; linha++) {
            for (var coluna = 0; coluna < outra.colunas; coluna++) {
                var soma = 0.0;
                for (var c = 0; c < colunas; c++) {
                    soma += get(linha, c) * outra.get(c, coluna);
                }
                nova.set(linha, coluna, soma);
            }
        }
        return nova;
    }

    public Matrix multiply(Matrix outra, int threads) throws InterruptedException {
        if (threads <= 0) throw new IllegalArgumentException("Deve ser executado com pelo menos uma thread.");
        if (outra == null || colunas != outra.linhas) {
            throw new IllegalArgumentException("As matrizes não têm tamanhos compatíveis para serem multiplicadas.");
        }
        var pool = Executors.newFixedThreadPool(threads);
        var nova = new Matrix(linhas, outra.colunas);
        for (var linha = 0; linha < linhas; linha++) {
            for (var coluna = 0; coluna < outra.colunas; coluna++) {
                var a = linha;
                var b = coluna;
                pool.submit(() -> {
                    var soma = 0.0;
                    for (int c = 0; c < colunas; c++) {
                        soma += get(a, c) * outra.get(c, b);
                    }
                    nova.set(a, b, soma);
                });
            }
        }
        pool.shutdown();
        while (!pool.isTerminated()) {
            pool.awaitTermination(999999, TimeUnit.DAYS);
        }
        return nova;
    }

    @Override
    public String toString() {
        var sb = new StringBuilder(linhas * colunas * 20);
        for (var linha = 0; linha < linhas; linha++) {
            for (var coluna = 0; coluna < colunas; coluna++) {
                sb.append(coluna == 0 ? "[" : " ").append(get(linha, coluna));
            }
            sb.append("]");
            if (linha != linhas - 1) sb.append("\n");
        }
        return sb.toString();
    }

    public static Matrix fromString(String in) {
        if (in == null) throw new IllegalArgumentException("Null não pode ser convertido em matriz.");
        var doubles = new ArrayList<Double>();
        var colunas = -1;
        var partes = in.split("\n");
        var linhas = 0;
        for (var parte: partes) {
            var p = parte.trim();
            if (p.endsWith("\r")) p = p.substring(0, p.length() - 1);
            if (p.isEmpty()) continue;
            if (!p.startsWith("[") || !p.endsWith("]")) {
                throw new IllegalArgumentException("A matriz não contém linhas delimitadas por [ e ] e separadas por uma quebra-de-linha.");
            }
            var itens = p.substring(1, p.length() - 1).split(" ");
            int colunasAqui = 0;
            for (String item : itens) {
                if (item.isEmpty()) continue;
                try {
                    doubles.add(Double.parseDouble(item));
                } catch (NumberFormatException e) {
                    throw new IllegalArgumentException("A matriz contém elementos que não podem ser convertidos para o formato numérico.");
                }
                colunasAqui++;
            }
            linhas++;
            if (colunas == -1) {
                colunas = colunasAqui;
            } else if (colunas != colunasAqui) {
                throw new IllegalArgumentException("A matriz contém linhas com tamanhos diferentes entre si ou não separadas corretamente.");
            }
        }
        var m = new Matrix(linhas, colunas);
        var it = doubles.iterator();
        for (var i = 0; i < linhas; i++) {
            for (var j = 0; j < colunas; j++) {
                m.set(i, j, it.next());
            }
        }
        return m;
    }

    public static Matrix lerDoArquivo(String arquivo) throws IOException {
        if (arquivo == null) throw new IllegalArgumentException();
        return Matrix.fromString(Files.readString(Paths.get(arquivo), StandardCharsets.UTF_8));
    }

    public void salvarNoArquivo(String arquivo) throws IOException {
        if (arquivo == null) throw new IllegalArgumentException();
        Files.writeString(Paths.get(arquivo), toString(), StandardCharsets.UTF_8);
    }

    public static void multiplicarEGerarRelatorio(String arquivo1, String arquivo2, String arquivo3) throws IOException, InterruptedException {
        var m1 = lerDoArquivo(arquivo1);
        var m2 = lerDoArquivo(arquivo2);
        var m3 = m1.multiply(m2, Runtime.getRuntime().availableProcessors());
        var relatorio = "Primeira matriz:\n" + m1.toString() + "\n\nSegunda matriz:\n" + m2.toString() + "\n\nMultiplicadas:\n" + m3.toString();
        Files.writeString(Paths.get(arquivo3), relatorio, StandardCharsets.UTF_8);
    }

    public static void main(String[] args) throws IOException, InterruptedException {
        var sc = new Scanner(System.in);
        System.out.println("Nome do arquivo com a matriz 1: ");
        var arquivo1 = sc.nextLine();
        System.out.println("Nome do arquivo com a matriz 2: ");
        var arquivo2 = sc.nextLine();
        System.out.println("Nome do arquivo de saída com o relatório: ");
        var arquivo3 = sc.nextLine();
        multiplicarEGerarRelatorio(arquivo1, arquivo2, arquivo3);
    }
}

I tested it with these two files:

[1 4 5 8 10]
[2 5 8 9 2]
[3 7 4 2 3]
[1 4]
[2 7]
[3 1]
[3 2]
[5 2]

By running it and entering the name of these two files (in order) and the name of a third file that is where the report should be saved, it generated a third file with this content:

Primeira matriz:
[1.0 4.0 5.0 8.0 10.0]
[2.0 5.0 8.0 9.0 2.0]
[3.0 7.0 4.0 2.0 3.0]

Segunda matriz:
[1.0 4.0]
[2.0 7.0]
[3.0 1.0]
[3.0 2.0]
[5.0 2.0]

Multiplicadas:
[98.0 73.0]
[73.0 73.0]
[50.0 75.0]

With the exception of the method fromString(Matrix), most of the code should be somewhat obvious and self-explanatory. The method fromString(Matrix) is responsible for reading a string and mounting to an array from it. This string has to be formed by lines starting with [ and ending with ] and separated by \n. Matrix elements are separated by spaces. It forgives extra blank spaces or blank lines that are left over.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.