【高并发系列】14、循环栅栏 CyclicBarrier

java.util.concurrent.CyclicBarrier与CountDownLatch非常类似,也可以实现线程间的计数等待,但其功能更为复杂强大;

Barrier意为栅栏,障碍物,阻止线程继续执行,要求在栅栏外等待;

Cyclic意为循环,这个计数器可以循环使用;

示例:司令要求10个士兵一起去完成一项任务;首先要求10个士兵集合报到,然后一起去执行任务,等10个士兵把各自任务都执行完了,司令才能宣布任务完成!

public class CyclicBarrierDemo {
	public static class Soldier implements Runnable {
		private String name;
		private CyclicBarrier cyclic;
		public Soldier(CyclicBarrier cyclic, String name) {
			this.cyclic = cyclic;
			this.name = name;
		}
		@Override
		public void run() {
			try {
				// 等待所有士兵到齐
				cyclic.await();
				doWork();
				// 等待所有士兵完成工作
				cyclic.await();
			} catch (InterruptedException e) {
				e.printStackTrace();
			} catch (BrokenBarrierException e) {
				e.printStackTrace();
			}
		}
		private void doWork() {
			try {
				TimeUnit.SECONDS.sleep(Math.abs(new Random().nextInt(9)));
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println(name + "'s work is done.");
		}
	}
	public static class BarrierRun implements Runnable {
		private boolean flag;
		int n;
		public BarrierRun(boolean flag, int n) {
			this.flag = flag;
			this.n = n;
		}
		@Override
		public void run() {
			if (flag) {
				System.out.println("The commander: There are " + n + " soldiers complete the task.");
			} else {
				System.out.println("The commander: There are " + n + " soldiers get together.");
				flag = true;
			}
		}
	}
	public static void main(String[] args) {
		final int n = 10;
		Thread[] allSoldiers = new Thread[n];
		boolean flag = false;
		CyclicBarrier cyclic = new CyclicBarrier(n, new BarrierRun(flag, n));
		System.out.println("Get together now!");
		for (int i = 0; i < n; i++) {
			String soldierName = "soldier" + i;
			System.out.println(soldierName + " arrivals.");
			allSoldiers[i] = new Thread(new Soldier(cyclic, soldierName));
			allSoldiers[i].start();
			//if(i == 5) {
			//	allSoldiers[i].interrupt();
			//}
		}
	}
}

每一个士兵线程都会执行Soldier类中的run()方法;第一个cyclic.await()方法,每一个士兵线程都会等待,直到10个士兵集合完毕,才会继续向下执行;

集合完毕意味着CyclicBarrier的一次计数完成,当再一次调用await()方法时,会进行下一次计数,即等10个士兵线程都完成各自任务后集合,司令宣布任务完成;

每一次计数完成后都会调用BarrierRun类中的run()方法;

把main方法中注释掉的代码恢复,会得到1个java.lang.InterruptedException和9个java.util.concurrent.BrokenBarrierException;其中InterruptedException是被中断线程抛出的,而BrokenBarrierException则是在等待当前CyclicBarrier上的线程抛出的,可以避免9个线程进行永久的、无谓的等待;

猜你喜欢

转载自blog.csdn.net/hellboy0621/article/details/87154582