0

もっと理解するために、オラクルページからCyclicBarrierコードを入手しました。私はそれを修正し、今1つの疑問があります。以下のコードは終了しませんが、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 が必要なのはなぜですか?

4

1 に答える 1

1

私はあなたのコードを実行していませんが、競合状態が発生している可能性があります。それを明らかにするシナリオは次のとおりです。

  • 最初のスレッドを開始すると、それはprocessRowメソッド呼び出しを終了するのに十分な一定の時間実行されるため、 doneを trueに設定してから、バリアを待機します。

  • 他のスレッドは開始しますが、すべてが「完了」していることを確認するため、ループには入らず、バリアを待つことはなく、直接終了します。

  • N 個のスレッドのうちの 1 つだけがバリアに到達したため、バリアがアクティブになることはありません

  • デッドロック

睡眠で機能する理由:

  • スレッドの 1 つがスリープ状態になると、その作業を「完了」としてマークする前に、他のスレッドを動作させます。

  • 他のスレッドには十分な時間があり、それ自体がバリアに到達できます

  • 5 スレッドが 10 ミリ秒を超えてはならない処理を終了するには、2 秒で十分です。

ただし、システムがオーバーロードされている場合、デッドロックが発生する可能性があることに注意してください。

  • 最初のスレッドがスリープを開始します

  • OS スケジューラが別のアプリケーションを 2 秒以上動作させている

  • OS スケジューラがアプリケーションに戻り、スレッド スケジューラが最初のスレッドを再度選択して終了させ、doneを trueに設定します。

  • ここでも最初のシナリオ =>デッドロック

そして可能な解決策(申し訳ありませんがテストされていません):

do/whileループの while ループを変更します。

do
{
    processRow(myRow);

    ...
}
while (!done);
于 2013-06-16T17:12:22.687 に答える