我从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?
答案 0 :(得分:1)
我没有运行您的代码,但可能存在竞争条件,这是一个揭示它的场景:
启动第一个线程,它会在一定时间内运行,足以完成 processRow 方法调用,因此它将 done 设置为true并且然后等待障碍,
其他线程开始,但他们发现所有“已完成”因此他们不会进入循环而他们永远不会等待障碍 ,并直接结束
屏障永远不会被激活,因为N个线程中只有一个已经到达
<强>死锁强>
为什么使用睡眠:
当其中一个线程开始进入睡眠状态时允许其他线程工作,然后将工作标记为“已完成”
其他线程有足够的时间工作,并且自己可以到达障碍
2秒足以让5个线程结束不超过10毫秒的处理
但是请注意,如果你的系统被加载了,它可能会陷入僵局:
第一个帖子开始入睡
操作系统调度程序允许其他应用程序超过2秒
OS调度程序返回到您的应用程序,线程调度程序再次选择第一个线程,让它终止,将 done 设置为true
这里又是第一个场景=&gt; 死锁也是
可能的解决方案(抱歉未经测试):
为执行/同时循环更改您的while循环:
do
{
processRow(myRow);
...
}
while (!done);