0

我从 oracle 页面获得了 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?

4

1 回答 1

1

我没有运行您的代码,但可能存在竞争条件,这是一个揭示它的场景:

  • 您启动第一个线程,它会在足以完成processRow方法调用的一定时间内运行,因此它将done设置为 true,然后在屏障上等待

  • 其他线程开始,但他们看到一切都“完成”,所以他们不进入循环,他们永远不会在屏障上等待,直接结束

  • 屏障永远不会被激活,因为只有 N 个线程中的一个已经到达它

  • 僵局

为什么它与sleep一起工作:

  • 当其中一个线程开始休眠时,它会让其他线程工作,然后将工作标记为“完成

  • 其他线程有足够的时间工作并且可以自己到达屏障

  • 2 秒足以让 5 个线程结束不应持续超过 10 毫秒的处理

但请注意,如果您的系统过载,它可能会死锁:

  • 第一个线程开始休眠

  • 操作系统调度程序让另一个应用程序在超过 2 秒的时间内工作

  • 操作系统调度程序返回到您的应用程序,线程调度程序再次选择第一个线程并让它终止,将done设置为 true

  • 这里又是第一个场景 =>死锁

和一个可能的解决方案(抱歉没有测试):

更改do/while循环的 while循环:

do
{
    processRow(myRow);

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