websofter
@websofter
Programmer...

Как выполнить цикл в потоке в Java/Thread?

Здравствуйте. Есть такой код класса, который определяет определитель матрицы. Алгоритм правильный, все работает, но мне нужно организовать указанные циклы for в потоках:
package determinant;

import java.util.ArrayList;

class  CMatrix{
public double determinant(double A[][],int N) throws InterruptedException
    {
        double det=0;
        if(N == 1)
        {
            det = A[0][0];
        }
        else if (N == 2)
        {
            det = A[0][0]*A[1][1] - A[1][0]*A[0][1];
        }
        else
        {       //--------------------------------

                //-------------------------------
            det=0;
            for(int j1=0;j1<N;j1++)
            {    
                double[][] m = new double[N-1][];
                //-----------Здесь главный поток в обычном режиме
                for(int k=0;k<(N-1);k++)//-----Надо это организовать в потоке
                {
                    m[k] = new double[N-1];
                }

                
                //
                for(int i=1;i<N;i++)//-----Надо это организовать в потоке
                {
                    int j2=0;
                    for(int j=0;j<N;j++)
                    {
                        if(j == j1)
                            continue;
                        m[i-1][j2] = A[i][j];
                        j2++;
                    }
                }
                //-----------Здесь главный поток в обычном режиме
                det += Math.pow(-1.0,1.0+j1+1.0)* A[0][j1] * determinant(m,N-1);
            }
        }
        return det;
    }
}


Хочу сделать вышеуказанные циклы в потоке с помощью класса Thread, но увы. Пытаюсь сделать это следующим образом, создавая отдельный класс:
/*
Класс для организации цикла в потоке
 */
package determinant;

/**
 *
 * @author WebSofter
 */
public class ThreadMethod1 implements Runnable//(содержащее метод run())
{ public int N;
  public double[][] m;
  
    void getM()
    {
        this.m = new double[this.N-1][];

        for(int k=0;k<(this.N-1);k++)
        {
            this.m[k] = new double[this.N-1];
        }
    }

    @Override
    public void run()		//Этот метод будет выполняться в побочном потоке
    {
        getM();
        //System.out.println("Привет из побочного потока!");
    }
}


И дальше использовать вместо цикла for вот так:
package determinant;

import java.util.ArrayList;

class  CMatrix{
public double determinant(double A[][],int N) throws InterruptedException
    {
        double det=0;
        if(N == 1)
        {
            det = A[0][0];
        }
        else if (N == 2)
        {
            det = A[0][0]*A[1][1] - A[1][0]*A[0][1];
        }
        else
        {       //--------------------------------

                //-------------------------------
            det=0;
            for(int j1=0;j1<N;j1++)
            {    
                double[][] m = new double[N-1][];
                //-----------Здесь главный поток в обычном режиме
                /*
                for(int k=0;k<(N-1);k++)//-----Надо это организовать в потоке
                {
                    m[k] = new double[N-1];
                }

                */
                ThreadMethod1 tm1 = new ThreadMethod1();
                tm1.N = N;
                Thread thread1 = new Thread(tm1);
                thread1.start();
                m = tm1.m;
                //
                Thread.currentThread().sleep(2);//Задержка главного потока
                //
                for(int i=1;i<N;i++)//-----Надо это организовать в потоке
                {
                    int j2=0;
                    for(int j=0;j<N;j++)
                    {
                        if(j == j1)
                            continue;
                        m[i-1][j2] = A[i][j];
                        j2++;
                    }
                }
                //-----------Здесь главный поток в обычном режиме
                det += Math.pow(-1.0,1.0+j1+1.0)* A[0][j1] * determinant(m,N-1);
            }
        }
        return det;
    }
}


Но выходит ошибка:
Exception in thread "main" java.lang.NullPointerException
	at determinant.CMatrix.determinant(CMatrix.java:48)
	at determinant.Determinant.main(Determinant.java:49)
Java Result: 1
СБОРКА УСПЕШНО ЗАВЕРШЕНА (общее время: 1 секунда)


Маленькая консольная программа, вычисляющая определитель матрицы из файла. Исходники
С задачей разбирает хорошо, но мне нужно использовать к этой программе потоки класса Thread, как показал выше, но пока печально. В чем моя ошибка?
  • Вопрос задан
  • 3869 просмотров
Пригласить эксперта
Ответы на вопрос 2
@iliyaisd
Судя по всему, вы пытаетесь получить данные от потока до того, как он завершил расчёт, и судя по ошибке - даже до того, как он успел проинициализировать переменную m. Вам нужно, чтобы поток выставлял какой-то флаг (создайте в его классе булевскую переменную), который означает, что расчёт завершён. Далее в цикле опрашиваете потоки на предмет конца расчётов. Я ж так понимаю, это некая имитация параллельного программирования? Если так, то вам нужно все потоки опрашивать на предмет этих флагов и объединять данные, когда все будут готовы.
Ответ написан
mrRontgen
@mrRontgen
Scala lover.
Попробуй вот так:
import java.util.concurrent.*;

class CMatrix {

    private double det = 0;

    int availableProcessors = Runtime.getRuntime().availableProcessors();
    ExecutorService executorService = Executors.newFixedThreadPool(availableProcessors);

    public void callback(Double[][] A, int N, Double[][] m, int j1) throws InterruptedException {
        det += Math.pow(-1.0, 1.0 + j1 + 1.0) * A[0][j1] * determinant(m, N - 1, false);
    }

    /**
     * 
     * @param A
     * @param N
     * @param isMain - if true then shutdown and await all threads
     * return
     * @throws InterruptedException
     */
    public double determinant(Double A[][], int N, boolean isMain) throws InterruptedException {
        //todo: if N=0
        if (N == 1) {
            det = A[0][0];
        } else if (N == 2) {
            det = A[0][0] * A[1][1] - A[1][0] * A[0][1];
        } else {
            for (int j1 = 0; j1 < N; j1++) {
                Calculate calculate = new Calculate(A, N, j1);
//                calculate.setcMatrix(this); //todo: you may call callback from other thread
                Future<Double[][]> result = executorService.submit(calculate);
                try {
                    callback(A, N, result.get(10, TimeUnit.SECONDS), j1);
                } catch (InterruptedException | ExecutionException | TimeoutException e) {
                    e.printStackTrace();
                }
            }
        }
        if (isMain) {
            executorService.shutdown(); //it just signal. System will wait for all task completed.
            executorService.awaitTermination(60, TimeUnit.MINUTES);
        }
        return det;
    }
}

class Calculate implements Callable<Double[][]> {

    private int N;

    private Double[][] A;

    private int j1;

    public Calculate(Double[][] a, int n, int j1) {
        N = n;
        A = a;
        this.j1 = j1;
    }

    private CMatrix cMatrix;

    public void setcMatrix(CMatrix cMatrix) {
        this.cMatrix = cMatrix;
    }

    public CMatrix getcMatrix() {
        return cMatrix;
    }

    @Override
    public Double[][] call() throws Exception {
        Double[][] m = new Double[N - 1][];
        for (int i = 1; i < N; i++) {//-----Надо это организовать в потоке
            int j2 = 0;
            for (int j = 0; j < N; j++) {
                if (j == j1)
                    continue;
                m[i - 1][j2] = A[i][j];
                j2++;
            }
        }
        return m;
    }
}


Многопоточный рекурсивные функции это по хардкорному. Я даже понятия не имею что там будет со стеками вызовов.
Может лучше сначала используя многопоточность посчитать определители всех дополнительных миноров и записать их с параметрами в какой нибудь LinkedList, а потом, когда все задачи отработали, в одном цикле в главном потоке посчитать определитель.

P.S. Посмотри еще forkjoin. Там есть RecursiveTask.

P.S.P.S. Вот тут рекурсивная сортировка docs.oracle.com/javase/8/docs/api/java/util/concur...
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы