我的目的很简单。
我想使用CyclicBarrier
和它的reset()
方法使用下面提到的代码运行3个线程4次。已经研究过net中的所有可能资源,实践中的并发和 Thinking in Java 。无法按照我想要的方式解决问题。
在 Thinking in Java 中,在HorseRace.Java下有一种此类解决方案,但它使用了Executor服务。我希望仅使用CyclicBarrier
和reset()
方法来做到这一点。这是我的代码和输出,它运行到结束但在reset()方法之后抛出BrokenBarrierException
。
package com.apal.barrier;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierEx1 {
CyclicBarrier cb;
public static int count = 0;
public static void main(String[] args) {
new CyclicBarrierEx1().manageThread();
}
private void manageThread() {
cb = new CyclicBarrier(3, new Runnable() {
@Override
public void run() {
if (count == 3) {
System.out.println("Exit from system");
return;
}
System.out.println("Collating task");
cb.reset();
for (int i = 0; i < 3; i++) {
new Thread(new Worker(cb)).start();
}
count++;
}
});
for (int i = 0; i < 3; i++) {
new Thread(new Worker(cb)).start();
}
}
}
class Worker implements Runnable {
CyclicBarrier cb;
public Worker(CyclicBarrier cb) {
this.cb = cb;
}
@Override
public void run() {
doSomeWork();
try {
cb.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
private void doSomeWork() {
System.out.println("Doing some work ");
}
}
示例输出
Doing some work
Doing some work
Doing some work
Collating task
Doing some work
Doing some work
Doing some work
Collating task
Doing some work
java.util.concurrent.BrokenBarrierExceptionDoing some work
Doing some work
Collating task
Doing some work
at java.util.concurrent.CyclicBarrier.dowait(Unknown Source)
at java.util.concurrent.CyclicBarrier.await(Unknown Source)
at com.apal.barrier.Worker.run(CyclicBarrierEx1.java:48)
at java.lang.Thread.run(Unknown Source)
java.util.concurrent.BrokenBarrierException
at java.util.concurrent.CyclicBarrier.dowait(Unknown Source)
at java.util.concurrent.CyclicBarrier.await(Unknown Source)
Doing some work at com.apal.barrier.Worker.run(CyclicBarrierEx1.java:48)
at java.lang.Thread.run(Unknown Source)
Doing some work
Exit from systemjava.util.concurrent.BrokenBarrierException
at java.util.concurrent.CyclicBarrier.dowait(Unknown Source)
at java.util.concurrent.CyclicBarrier.await(Unknown Source)
at com.apal.barrier.Worker.run(CyclicBarrierEx1.java:48)
at java.lang.Thread.run(Unknown Source)
java.util.concurrent.BrokenBarrierException
at java.util.concurrent.CyclicBarrier.dowait(Unknown Source)
at java.util.concurrent.CyclicBarrier.await(Unknown Source)
at com.apal.barrier.Worker.run(CyclicBarrierEx1.java:48)
at java.lang.Thread.run(Unknown Source)
java.util.concurrent.BrokenBarrierException
at java.util.concurrent.CyclicBarrier.dowait(Unknown Source)
at java.util.concurrent.CyclicBarrier.await(Unknown Source)
at com.apal.barrier.Worker.run(CyclicBarrierEx1.java:48)
at java.lang.Thread.run(Unknown Source)
java.util.concurrent.BrokenBarrierException
at java.util.concurrent.CyclicBarrier.dowait(Unknown Source)
at java.util.concurrent.CyclicBarrier.await(Unknown Source)
at com.apal.barrier.Worker.run(CyclicBarrierEx1.java:48)
at java.lang.Thread.run(Unknown Source)
答案 0 :(得分:2)
当运行CyclicBarrier
构造函数中传递的屏障操作时,您有一个竞争条件。 The docs for CyclicBarrier.await()
说明了如何运行该操作方法(强调添加):
如果当前线程是最后到达的线程,则为非null 在构造函数中提供了障碍动作,然后当前 线程在允许其他线程继续之前运行该操作。
这意味着屏障操作方法对reset()
的调用可能会发生,而其他线程仍然在屏障上等待。这将产生BrokenBarrierException
。
请参阅以&#34开头的段落的文档;如果屏障操作不依赖于执行时被暂停的各方,则该方中的任何线程都可以在发布时执行该操作&# 34 ;.使用该技术,您可以在从await()
释放之后的一个工作线程中执行您当前在操作例程中执行的工作。以下是未经测试的尝试(注意 - 我还重新调整了count
变量增加的位置以避免工作线程可能在count
变为递增之前完成的竞争条件:
package com.apal.barrier;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierEx1 {
CyclicBarrier cb;
public static int count = 0;
public static void main(String[] args) {
new CyclicBarrierEx1().manageThread();
}
public static void barrierComplete(CyclicBarrier cb) {
System.out.println("Collating task");
if (count == 3) {
System.out.println("Exit from system");
return;
}
count++;
for (int i = 0; i < 3; i++) {
new Thread(new Worker(cb)).start();
}
}
private void manageThread() {
cb = new CyclicBarrier(3);
for (int i = 0; i < 3; i++) {
new Thread(new Worker(cb)).start();
}
}
}
class Worker implements Runnable {
CyclicBarrier cb;
public Worker(CyclicBarrier cb) {
this.cb = cb;
}
@Override
public void run() {
doSomeWork();
try {
if (cb.await() == 0) {
CyclicBarrierEx1.barrierComplete(cb);
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
private void doSomeWork() {
System.out.println("Doing some work ");
}
}
答案 1 :(得分:0)
从MichaelBurr的提示中获取想法,检查在Worker线程中没有等待线程计数来重置CyclicBarrier同步器。我发布了自己的答案,因为我真的想使用CyclicBarrier和reset()方法来实现多次运行线程并整理他们的任务,比如Matrix操作。
package com.apal.barrier;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierEx1 {
CyclicBarrier cb;
public static int count = 0;
public static void main(String[] args) {
new CyclicBarrierEx1().manageThread();
}
private void manageThread() {
cb = new CyclicBarrier(3, new Runnable() {
@Override
public void run() {
if (count == 3) {
System.out.println("Exit from system");
return;
}
System.out.println("Collating task");
count++;
// cb.reset(); **Commented and replaced in Worker**
for (int i = 0; i < 3; i++) {
new Thread(new Worker(cb)).start();
}
}
});
for (int i = 0; i < 3; i++) {
new Thread(new Worker(cb)).start();
}
}
}
class Worker implements Runnable {
CyclicBarrier cb;
public Worker(CyclicBarrier cb) {
this.cb = cb;
}
@Override
public void run() {
doSomeWork();
try {
cb.await();
//if (cb.getNumberWaiting() == 0) // **if no one is waiting, then reset it.**
// cb.reset();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
private void doSomeWork() {
System.out.println("Doing some work ");
}
}
示例输出
Doing some work
Doing some work
Doing some work
Collating task
Doing some work
Doing some work
Doing some work
Collating task
Doing some work
Doing some work
Doing some work
Collating task
Doing some work
Doing some work
Doing some work
Exit from system
从Javadoc进行重置()
将屏障重置为其初始状态。如果当前有任何一方 在障碍物等待,他们将返回 BrokenBarrierException。请注意,发生破损后重置 由于其他原因可能会很复杂;线程需要 以其他方式重新同步,并选择一个执行重置。 可能最好为后续创建一个新的障碍 使用
因此,重置会导致任何当前正在等待的线程抛出BrokenBarrierException并立即唤醒。当你想要“打破”屏障时使用重置。
在正常情况下,永远不需要使用reset()。