CyclicBarrier код не работает?
Я получил код CyclicBarrier со страницы оракула, чтобы понять его больше. Я изменил это и теперь с одним сомнением. Приведенный ниже код не завершается, но если я раскомментирую условие Thread.sleep, оно будет работать нормально.
import java.util.Arrays;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
class Solver {
final int N;
final float[][] data;
boolean done = false;
final CyclicBarrier barrier;
class Worker implements Runnable {
int myRow;
Worker(int row) {
myRow = row;
}
public void run() {
while (!done) {
processRow(myRow);
try {
barrier.await();
} catch (InterruptedException ex) {
return;
} catch (BrokenBarrierException ex) {
return;
}
}
System.out.println("Run finish for " + Thread.currentThread().getName());
}
private void processRow(int row) {
float[] rowData = data[row];
for (int i = 0; i < rowData.length; i++) {
rowData[i] = 1;
}
/*try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}*/
done = true;
}
}
public Solver(float[][] matrix) {
data = matrix;
N = matrix.length;
barrier = new CyclicBarrier(N, new Runnable() {
public void run() {
for (int i = 0; i < data.length; i++) {
System.out.println("Data " + Arrays.toString(data[i]));
}
System.out.println("Completed:");
}
});
for (int i = 0; i < N; ++i)
new Thread(new Worker(i), "Thread "+ i).start();
}
}
public class CyclicBarrierTest {
public static void main(String[] args) {
float[][] matrix = new float[5][5];
Solver solver = new Solver(matrix);
}
}
Почему Thread.sleep требуется в приведенном выше коде?
1 ответ
Я не запускал ваш код, но может быть условие гонки, вот сценарий, который показывает это:
вы запускаете первый поток, он запускается в течение определенного времени, достаточного для завершения вызова метода processRow, поэтому он устанавливает значение done в true изатем ожидает на барьере,
другие потоки запускаются, но они видят, что все " сделано", поэтому они не входят в цикл иникогда не будут ждать на барьере, а заканчиваются напрямую
барьер никогда не будет активирован, так как только один из N потоков достиг его
тупик
Почему это работает сосном:
когда один из потоков начинает спать, онпозволяет другим потокам работать, прежде чем помечать работу каквыполненную.
другие нити имеют достаточно времени для работы и могут сами достичь барьера
2 секунды достаточно для того, чтобы 5 потоков завершили обработку, которая не должна длиться дольше 10 мс
Но обратите внимание, что если ваша система перегружена, она может зайти в тупик:
первый потокначинает спать
планировщик ОС позволяет другому приложению работать более 2 секунд
планировщик ОС возвращается к вашему приложению, а планировщик потоков снова выбирает первый поток ипозволяет ему завершиться, установив true в значение true
и здесь опять первый сценарий => тупик тоже
И возможное решение (извините, не проверено):
измените ваши циклы while для циклов do/while:
do
{
processRow(myRow);
...
}
while (!done);