CyclicBarrier(栅栏):拦截一组线程并使其阻塞,直到其内部的计数器归零,再唤醒所有的阻塞线程继续执行任务。
public class CyclicBarrier {
private static class Generation {
boolean broken = false;
}
// 可重入锁
private final ReentrantLock lock = new ReentrantLock();
// 提供trip.await();使线程阻塞 trip.signalAll(); 唤醒所有阻塞线程等方法
private final Condition trip = lock.newCondition();
// 计数器归零时,执行的任务
private final Runnable barrierCommand;
// 阻塞线程数
private final int parties;
// 代,一次成功或异常的操作都会使其更新换代,也是CyclicBarrier可循环使用的原因
private Generation generation = new Generation();
// 根据parties初始化计数器个数
private int count;
...
public CyclicBarrier(int parties) {
this(parties, null);
}
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}
参数parties:初始化计数器计量个数count。
参数barrierAction:当计数器count归零时,先执行下barrierAction任务,再唤醒阻塞线程。
await():计数器count > 0,使调用线程阻塞;= 0,唤醒所有阻塞线程。
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe);
}
}
public int await(long timeout, TimeUnit unit)
throws InterruptedException,
BrokenBarrierException,
TimeoutException {
return dowait(true, unit.toNanos(timeout));
}
最终调用的dowait()方法
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException, TimeoutException {
// 可重入锁 ReentrantLock
final ReentrantLock lock = this.lock;
lock.lock();
try {
// 当前代
final Generation g = generation;
// 检查当前broken是否损坏,一组线程中有等待超时、中断或者reset重置
if (g.broken)
throw new BrokenBarrierException();
// 当前线程是否中断
if (Thread.interrupted()) {
// 将broken状态设置为true
// 重置计数器count
// 唤醒线程
breakBarrier();
throw new InterruptedException();
}
// 计数器减一
int index = --count;
// 计数器为零
if (index == 0) {
boolean ranAction = false;
try {
// 构造器有带任务则先执行任务动作
final Runnable command = barrierCommand;
if (command != null) command.run();
// 任务正常,没有抛出异常
ranAction = true;
// 重置count
// 唤醒线程
// 更新换代,generation = new Generation();
nextGeneration();
return 0;
} finally {
// 任务异常
if (!ranAction) breakBarrier();
}
}
// 计数器不为0,循环
for (;;) {
try {
// 等待时间限制
if (!timed) trip.await();
else if (nanos > 0L) nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
if (g == generation && ! g.broken) {
breakBarrier();
throw ie;
} else {
// We're about to finish waiting even if we had not
// been interrupted, so this interrupt is deemed to
// "belong" to subsequent execution.
Thread.currentThread().interrupt();
}
}
// broken是否损坏
if (g.broken) throw new BrokenBarrierException();
// 计数器为零的时候,会创建新的generation,使新旧不一致,以此跳出循环
if (g != generation) return index;
// 等待超时
if (timed && nanos <= 0L) {
breakBarrier();
throw new TimeoutException();
}
}
} finally {
lock.unlock();
}
}
public static void demo01() throws Exception {
CyclicBarrier barrier = new CyclicBarrier(4);
Thread t1 = new Thread(getRunnable(barrier), "t1");
Thread t2 = new Thread(getRunnable(barrier), "t2");
Thread t3 = new Thread(getRunnable(barrier), "t3");
t1.start();
t2.start();
t3.start();
Thread.sleep(3000);
System.out.println("所有人准备完毕,开始鸣枪!");
barrier.await();
}
private static Runnable getRunnable(CyclicBarrier barrier) {
return () -> {
String thName = Thread.currentThread().getName();
try {
System.out.println("选手:" + thName + "准备就绪");
barrier.await();
long start = System.currentTimeMillis();
Thread.sleep((long) (Math.random() * 10000));
System.out.println("选手:" + thName + "跑完全程耗时:" + (System.currentTimeMillis() - start));
} catch (BrokenBarrierException e) {
System.out.println(thName + " broken");
} catch (InterruptedException e) {
System.out.println(thName + " 线程中断");
}
};
}
public static void demo02() throws Exception {
CyclicBarrier barrier = new CyclicBarrier(4, () -> {
try {
System.out.println(Thread.currentThread().getName() + " 准备鸣枪!");
Thread.sleep(3000);
System.out.println(Thread.currentThread().getName() + " 开始鸣枪!");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
Thread t1 = new Thread(getRunnable2(barrier), "t1");
Thread t2 = new Thread(getRunnable2(barrier), "t2");
Thread t3 = new Thread(getRunnable2(barrier), "t3");
t1.start();
t2.start();
t3.start();
Thread.sleep(2000);
barrier.await();
System.out.println("计数器归零");
}
private static Runnable getRunnable2(CyclicBarrier barrier) {
return () -> {
String thName = Thread.currentThread().getName();
try {
System.out.println("选手:" + thName + "准备就绪");
barrier.await();
long start = System.currentTimeMillis();
Thread.sleep((long) (Math.random() * 10000));
System.out.println("选手:" + thName + "跑完全程耗时:" + (System.currentTimeMillis() - start));
} catch (BrokenBarrierException e) {
System.out.println(thName + " broken");
} catch (InterruptedException e) {
System.out.println(thName + " 线程中断");
}
};
}
await():设置参数时,当前线程阻塞时间超过该参数时间,则会抛出TimeoutException异常
public static void demo03() throws Exception {
CyclicBarrier barrier = new CyclicBarrier(4);
Thread t1 = new Thread(getRunnable3(barrier), "t1");
Thread t2 = new Thread(getRunnable3(barrier), "t2");
Thread t3 = new Thread(getRunnable3(barrier), "t3");
t1.start();
t2.start();
t3.start();
Thread.sleep(5000);
System.out.println("所有人准备完毕,开始鸣枪!");
barrier.await();
}
private static Runnable getRunnable3(CyclicBarrier barrier) {
return () -> {
String thName = Thread.currentThread().getName();
try {
System.out.println("选手:" + thName + "准备就绪");
if ("t2".equals(Thread.currentThread().getName())) {
barrier.await(3000, TimeUnit.MILLISECONDS);
} else {
barrier.await();
}
long start = System.currentTimeMillis();
Thread.sleep((long) (Math.random() * 10000));
System.out.println("选手:" + thName + "跑完全程耗时:" + (System.currentTimeMillis() - start));
} catch (BrokenBarrierException e) {
System.out.println(thName + " broken损坏");
} catch (InterruptedException e) {
System.out.println(thName + " 线程中断");
} catch (TimeoutException e) {
System.out.println(thName + " 等待超时");
}
};
}
interrupt():线程中断,抛出InterruptedException异常
public static void demo04() throws Exception {
CyclicBarrier barrier = new CyclicBarrier(4);
Thread t1 = new Thread(getRunnable4(barrier), "t1");
Thread t2 = new Thread(getRunnable4(barrier), "t2");
Thread t3 = new Thread(getRunnable4(barrier), "t3");
t1.start();
t2.start();
t3.start();
Thread.sleep(1000);
t2.interrupt();
Thread.sleep(5000);
System.out.println("所有人准备完毕,开始鸣枪!");
barrier.await();
}
private static Runnable getRunnable4(CyclicBarrier barrier) {
return () -> {
String thName = Thread.currentThread().getName();
try {
System.out.println("选手:" + thName + "准备就绪");
barrier.await();
long start = System.currentTimeMillis();
Thread.sleep((long) (Math.random() * 10000));
System.out.println("选手:" + thName + "跑完全程耗时:" + (System.currentTimeMillis() - start));
} catch (BrokenBarrierException e) {
System.out.println(thName + " broken损坏");
} catch (InterruptedException e) {
System.out.println(thName + " 线程中断");
}
};
}
reset():更新换代,重置前后调用await的线程处于不同的代
public void reset() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
// 将broken状态设置为true
// 重置count
// 唤醒线程
breakBarrier();
// 更新换代
nextGeneration();
} finally {
lock.unlock();
}
}
public static void demo05() throws Exception {
CyclicBarrier barrier = new CyclicBarrier(4);
Thread t1 = new Thread(getRunnable5(barrier), "t1");
Thread t2 = new Thread(getRunnable5(barrier), "t2");
Thread t3 = new Thread(getRunnable5(barrier), "t3");
t1.start();
t2.start();
t3.start();
Thread.sleep(5000);
System.out.println("重置、更新换代");
barrier.reset();
System.out.println("所有人准备完毕,开始鸣枪!");
barrier.await();
}
private static Runnable getRunnable5(CyclicBarrier barrier) {
return () -> {
String thName = Thread.currentThread().getName();
try {
System.out.println("选手:" + thName + "准备就绪");
barrier.await();
long start = System.currentTimeMillis();
Thread.sleep((long) (Math.random() * 10000));
System.out.println("选手:" + thName + "跑完全程耗时:" + (System.currentTimeMillis() - start));
} catch (BrokenBarrierException e) {
System.out.println(thName + " broken损坏");
} catch (InterruptedException e) {
System.out.println(thName + " 线程中断");
}
};
}
public static void demo05() throws Exception {
CyclicBarrier barrier = new CyclicBarrier(4);
Thread t1 = new Thread(getRunnable5(barrier), "t1");
Thread t2 = new Thread(getRunnable5(barrier), "t2");
Thread t3 = new Thread(getRunnable5(barrier), "t3");
t1.start();
t2.start();
t3.start();
Thread.sleep(5000);
//System.out.println("重置、更新换代");
//barrier.reset();
Thread t4 = new Thread(getRunnable5(barrier), "t4");
t4.start();
System.out.println("所有人准备完毕,开始鸣枪!");
barrier.await();
}
private static Runnable getRunnable5(CyclicBarrier barrier) {
return () -> {
String thName = Thread.currentThread().getName();
try {
System.out.println("选手:" + thName + "准备就绪");
// 重置
if ("t2".equals(thName)) {
barrier.reset();
}
barrier.await();
long start = System.currentTimeMillis();
Thread.sleep((long) (Math.random() * 10000));
System.out.println("选手:" + thName + "跑完全程耗时:" + (System.currentTimeMillis() - start));
} catch (BrokenBarrierException e) {
System.out.println(thName + " broken损坏");
} catch (InterruptedException e) {
System.out.println(thName + " 线程中断");
}
};
}
CountDownLatch:是一个同步工具类,用来协调多个线程之间的同步,或者说起到线程之间的通信作用。
CountDownLatch能够使一个线程在等待另外一些线程完成各自工作之后,再继续执行。
内部有计数器,计数器初始值为线程的数量。每当一个线程完成自己任务后,计数器的值就会减一。当计数器的值为0时,表示所有的线程都已经完成一些任务,然后在CountDownLatch上等待的线程就可以恢复执行接下来的任务。
countDown:使CountDownLatch内部计数器减一,当计数器归零时,唤醒线程
public void countDown() {
sync.releaseShared(1);
}
await:使当前线程在计数器归零前一直等待,除非线程被中断或超出了指定的等待时间。
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
public boolean await(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
private static void demo_01() {
final CountDownLatch latch = new CountDownLatch(3);
Thread t1 = new Thread(getRunnable(latch), "t1");
Thread t2 = new Thread(getRunnable(latch), "t2");
Thread t3 = new Thread(getRunnable(latch), "t3");
t1.start();
t2.start();
t3.start();
try {
latch.await();//阻塞当前线程,直到计数器归零
System.out.println("所有参赛人员已完成比赛,下面进行统计");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static Runnable getRunnable(CountDownLatch latch) {
return () -> {
String thName = Thread.currentThread().getName();
try {
System.out.println("选手:" + thName + "准备就绪");
long start = System.currentTimeMillis();
Thread.sleep((long) (Math.random() * 10000));
System.out.println("选手:" + thName + "跑完全程耗时:" + (System.currentTimeMillis() - start));
latch.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
};
}
private static void demo_02() {
final CountDownLatch referee = new CountDownLatch(1);
final CountDownLatch players = new CountDownLatch(4);
Thread t1 = new Thread(getRunnable2(referee, players), "t1");
Thread t2 = new Thread(getRunnable2(referee, players), "t2");
Thread t3 = new Thread(getRunnable2(referee, players), "t3");
Thread t4 = new Thread(getRunnable2(referee, players), "t4");
t1.start();
t2.start();
t3.start();
t4.start();
try {
Thread.sleep(3000);
System.out.println("裁判:" + Thread.currentThread().getName() + " 开始鸣枪!");
referee.countDown();
players.await();
System.out.println("比赛结束");
System.out.println("裁判:" + Thread.currentThread().getName() + "汇总成绩排名");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static Runnable getRunnable2(CountDownLatch referee, CountDownLatch players) {
return () -> {
String thName = Thread.currentThread().getName();
try {
System.out.println("选手:" + thName + " 准备就绪");
referee.await();
System.out.println("选手:" + thName + " 鸣枪开跑");
long start = System.currentTimeMillis();
Thread.sleep((long) (Math.random() * 10000));
System.out.println("选手:" + thName + " 到达终点耗时:" + (System.currentTimeMillis() - start));
players.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
};
}
CyclicBarrier是可重复使用的,CountDownLatch是一次性的;
CyclicBarrier调用方法await就可以进行减一和线程阻塞操作,CountDownLatch通过方法countDown减一和方法await阻塞线程;
CyclicBarrier计数器归零时可以执行额外任务,CountDownLatch不可以;