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);
Другие вопросы по тегам