cyclicbarrier关注的是同一时刻并发执行,在同一个起跑线,在全部线程等待就绪了可以有一个操作
countdownlatch关注的是所有线程都执行完毕
一个经典的场景是:
一个任务有12步,然后要求第三步起每一步都要同时执行(每次同时执行条件满足需要输出一个提示),现在假设有4个任务一个任务起一个线程在所有线程结束后打印结束提示然后整个主线程结束。
在上面的场景中利用countdownlatch和cyclicbarrier结合会很好。
下面的例子描述了上面的一个简单版本(每一个任务共5步,等待step4,step4之前确保每一步的处理不会同时执行)
package cn.miaofahuacheng;
import java.io.FileNotFoundException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;
import org.junit.Test;
public class CyclicBarrierTest {
private static final int COUNT = 4;
private static final int SLEEP = 1000;
private static final Object LOCK = new Object();
private static final String TIME_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS";
private static synchronized void log(String msg) {
System.out.println(Thread.currentThread().getName() + "\t" + msg);
}
private static interface Step {
void run();
}
private static class Step1 implements Step {
@Override
public void run() {
try {
Thread.sleep(new Random().nextInt(SLEEP));
log(new SimpleDateFormat().format(new Date()) + "run 1"
+ getClass().getName());
Thread.sleep(new Random().nextInt(SLEEP));
log(new SimpleDateFormat(TIME_FORMAT).format(new Date()) + "run 2"
+ getClass().getName());
Thread.sleep(new Random().nextInt(SLEEP));
log(new SimpleDateFormat(TIME_FORMAT).format(new Date()) + "run 3"
+ getClass().getName());
Thread.sleep(new Random().nextInt(SLEEP));
log(new SimpleDateFormat(TIME_FORMAT).format(new Date()) + "run 4"
+ getClass().getName());
Thread.sleep(new Random().nextInt(SLEEP));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
log(new SimpleDateFormat(TIME_FORMAT).format(new Date()) + "run " + getClass().getName());
}
}
private static class Step2 implements Step {
@Override
public void run() {
try {
Thread.sleep(new Random().nextInt(SLEEP));
log(new SimpleDateFormat(TIME_FORMAT).format(new Date()) + "run 1"
+ getClass().getName());
Thread.sleep(new Random().nextInt(SLEEP));
log(new SimpleDateFormat(TIME_FORMAT).format(new Date()) + "run 2"
+ getClass().getName());
Thread.sleep(new Random().nextInt(SLEEP));
log(new SimpleDateFormat(TIME_FORMAT).format(new Date()) + "run 3"
+ getClass().getName());
Thread.sleep(new Random().nextInt(SLEEP));
log(new SimpleDateFormat(TIME_FORMAT).format(new Date()) + "run 4"
+ getClass().getName());
Thread.sleep(new Random().nextInt(SLEEP));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
log(new SimpleDateFormat(TIME_FORMAT).format(new Date()) + "run " + getClass().getName());
}
}
private static class Step3 implements Step {
@Override
public void run() {
try {
Thread.sleep(new Random().nextInt(SLEEP));
log(new SimpleDateFormat(TIME_FORMAT).format(new Date()) + "run 1"
+ getClass().getName());
Thread.sleep(new Random().nextInt(SLEEP));
log(new SimpleDateFormat(TIME_FORMAT).format(new Date()) + "run 2"
+ getClass().getName());
Thread.sleep(new Random().nextInt(SLEEP));
log(new SimpleDateFormat(TIME_FORMAT).format(new Date()) + "run 3"
+ getClass().getName());
Thread.sleep(new Random().nextInt(SLEEP));
log(new SimpleDateFormat(TIME_FORMAT).format(new Date()) + "run 4"
+ getClass().getName());
Thread.sleep(new Random().nextInt(SLEEP));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
log(new SimpleDateFormat(TIME_FORMAT).format(new Date()) + "run " + getClass().getName());
}
}
private static class Step4 implements Step {
@Override
public void run() {
try {
Thread.sleep(new Random().nextInt(SLEEP));
log(new SimpleDateFormat(TIME_FORMAT).format(new Date()) + "run 1"
+ getClass().getName());
Thread.sleep(new Random().nextInt(SLEEP));
log(new SimpleDateFormat(TIME_FORMAT).format(new Date()) + "run 2"
+ getClass().getName());
Thread.sleep(new Random().nextInt(SLEEP));
log(new SimpleDateFormat(TIME_FORMAT).format(new Date()) + "run 3"
+ getClass().getName());
Thread.sleep(new Random().nextInt(SLEEP));
log(new SimpleDateFormat(TIME_FORMAT).format(new Date()) + "run 4"
+ getClass().getName());
Thread.sleep(new Random().nextInt(SLEEP));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
log(new SimpleDateFormat(TIME_FORMAT).format(new Date()) + "run " + getClass().getName());
}
}
private static class Step5 implements Step {
@Override
public void run() {
try {
Thread.sleep(new Random().nextInt(SLEEP));
log(new SimpleDateFormat(TIME_FORMAT).format(new Date()) + "run 1"
+ getClass().getName());
Thread.sleep(new Random().nextInt(SLEEP));
log(new SimpleDateFormat(TIME_FORMAT).format(new Date()) + "run 2"
+ getClass().getName());
Thread.sleep(new Random().nextInt(SLEEP));
log(new SimpleDateFormat(TIME_FORMAT).format(new Date()) + "run 3"
+ getClass().getName());
Thread.sleep(new Random().nextInt(SLEEP));
log(new SimpleDateFormat(TIME_FORMAT).format(new Date()) + "run 4"
+ getClass().getName());
Thread.sleep(new Random().nextInt(SLEEP));
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
log(new SimpleDateFormat(TIME_FORMAT).format(new Date()) + "run " + getClass().getName());
}
}
private static class StepManager {
private static final CyclicBarrier CYCLICBARIER = new CyclicBarrier(COUNT, () -> {
log("all step manager come to same step");
});
private List<Step> stpes = new ArrayList<Step>();
public StepManager(List<Step> stpes) {
this.stpes.clear();
for (Step step : stpes) {
this.stpes.add(step);
}
}
public void runAll() {
for (Step i : stpes) {
try {
if (i instanceof Step4) {
log("awit...");
CYCLICBARIER.await();
}
if (i instanceof Step1 || i instanceof Step2 || i instanceof Step3) {
synchronized (LOCK) {
i.run();
}
} else {
i.run();
}
} catch (InterruptedException | BrokenBarrierException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
@Test
public void test() throws InterruptedException, FileNotFoundException {
final long timestamp = System.currentTimeMillis();
final Thread main = new Thread() {
public void run() {
final CountDownLatch mainCountDownLatch = new CountDownLatch(COUNT);
for (int i = 0; i < COUNT; ++i) {
List<Step> steps = new ArrayList<>(5);
steps.add(new Step1());
steps.add(new Step2());
steps.add(new Step3());
steps.add(new Step4());
steps.add(new Step5());
Thread thread = new Thread(() -> {
new StepManager(steps).runAll();
mainCountDownLatch.countDown();
});
thread.setName("test" + i);
thread.start();
}
try {
mainCountDownLatch.await();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
main.setName("main");
main.start();
main.join();
log("end cost " + (System.currentTimeMillis()-timestamp) + "ms");
}
}