Java: поток, разделенный на блоки, массив — служба исполнителя

#java #multithreading #executorservice

#java #многопоточность #executorservice

Вопрос:

Я создаю программу для вычисления значений двух массивов на этапах моделирования (они инициализируются с самого начала, я не ставил это здесь). Я хотел бы сделать это с помощью потоков и ExecutorService. Я разделил массивы на блоки и хочу, чтобы значения этих блоков вычислялись потоками, один блок = один поток. Эти два массива — X и Y — принимают значения друг от друга (как вы можете видеть в run()), я хочу, чтобы сначала вычислялся X, а затем Y, поэтому я создал два отдельных runnables:

 public static class CountX implements Runnable {
    private int start;
    private int end;
    private CountDownLatch cdl;
    public CountX(int s, int e, CountDownLatch c) {
        this.start = s;
        this.end = e;
        this.cdl = c;
    }
    public void run() {
        for (int i = start   1; i < end - 1; i  ) {
            x[i] = x[i] - (y[i-1] - 2 * y[i]   y[i 1])   y[i];
        }
        cdl.countDown();            
    }
}
 

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

Вот, вкратце, как выглядит мой майн, и это моя главная проблема:

 int NN = 400; //length of X and Y
int threads = 8;
int block_size = (int) NN/threads;

final ExecutorService executor_X = Executors.newFixedThreadPool(threads); 
final ExecutorService executor_Y = Executors.newFixedThreadPool(threads);
CountDownLatch cdl = new CountDownLatch(threads);
    
CountX[] runnables_X = new CountX[threads];
CountY[] runnables_Y = new CountY[threads];

for (int r = 0; r < threads; r  ) {
        runnables_X[r] = new CountX((r*block_size), ((r 1)*block_size), cdl); 
}
for (int r = 0; r < threads; r  ) {
        runnables_Y[r] = new CountY((r*block_size), ((r 1)*block_size), cdl);
}


int sim_steps = 4000;
for(int m = 0; m < sim_steps; m  ) {
    for (int e = 0; e < threads; e  ) {
        executor_X.execute(runnables_X[e]);
    }
    for (int e = 0; e < threads; e  ) {
        executor_Y.execute(runnables_Y[e]);
    }
}
executor_X.shutdown();
executor_Y.shutdown();
 

Я получаю неправильные значения массивов X и Y из этой программы, потому что я также делал это без потоков.
Необходим ли здесь CountDownLatch? Должен ли я выполнять цикл for runnables_X[r] = new CountX((r*block_size), ((r 1)*block_size), cdl); в каждом цикле m (sim_step)? Или, может быть, мне следует использовать ExecutorService по-другому? Я перепробовал много вариантов, но результаты по-прежнему неверны.
Заранее благодарю вас!

Ответ №1:

Ваш подход — это тот, который я, вероятно, не принял бы для этой задачи.

Вы можете работать со ссылками и исполняемыми файлами, но в вашем случае вызываемый объект может быть лучшим выбором. С помощью вызываемого объекта вы просто предоставляете ему массив и позволяете ему вычислять частичное значение, если это возможно, и ожидаете Futures . Для меня не совсем ясно, что вы на самом деле хотите вычислить, поэтому я беру слепое предположение здесь.

Вам не нужно CountDownLatch ни одного, ни двух ExecutorServices — достаточно одного EXS.

Если вы действительно хотите использовать a Runnable для этого, вам следует реализовать какую-то синхронизацию, либо с параллельным списком, атомарными переменными, volatile либо с блокировкой.

Комментарии:

1. Я вычисляю значения X и Y, которые находятся в run() исполняемых файлов

2. Это немного шире. Вы только поделились своим вычислением x, которое каким-то образом связано со значениями y . Когда x зависит от y, который должен быть вычислен первым, вы должны сначала выполнить вычисление y, дождаться результатов, а затем вычислить x. Кроме того, массивы не являются потокобезопасными.

3. y также зависит от x так же, как x зависит от y . В любом случае спасибо! Я постараюсь работать с Callable здесь.