CountDownLatch和CyclicBarrier

本文深入解析了并发编程中CountDownLatch和CyclicBarrier的使用方法及应用场景。CountDownLatch适用于某些代码需等待先决条件处理完毕后执行的情况,如同接力赛。而CyclicBarrier则更像团队赛,所有线程必须到达终点才能继续,适用于N个线程相互等待的场景。

并发编程常用工具类之CountDownLatch和CyclicBarrier的使用笔记。

CountDownLatch

在java1.5被引入,存在于java.util.cucurrent包下,也被称为:闭锁。
常用的并发工具类。

利用计数器的方式实现的多线程之间的同步方案。

典型的应用场景:某个线程的执行需要等待其他线程执行完毕完才开始。

例如:业务线程需要等待两个初始化线程执行完之后才能开始执行。

public class CountDownLatchDemo {
	//构建3个扣除点的CountDownLatch实例
	final static CountDownLatch LATCH = new CountDownLatch(2);

	//初始化线程A
	private static class InitThreadA extends Thread{
		@Override
		public void run() {
			System.out.println("开始初始化A...");
			SleepUtil.SEC.sleep(1);
			System.out.println("初始化A完毕.");
			//扣除点-1
			LATCH.countDown();
		}
	}

	//初始化线程B
	private static class InitThreadB extends Thread{
		@Override
		public void run() {
			System.out.println("开始初始化B...");
			SleepUtil.SEC.sleep(1);
			System.out.println("初始化B完毕.");
			//扣除点-1
			LATCH.countDown();
		}
	}

	//业务线程
	private static class BusiThread extends Thread{
		@Override
		public void run() {
			try {
				//阻塞 等待扣除点扣除完毕,才执行业务代码
				LATCH.await();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			System.out.println("执行业务代码...");
		}
	}

	public static void main(String[] args) throws InterruptedException {
		new BusiThread().start();
		new InitThreadA().start();
		new InitThreadB().start();
	}
}

输出如下:

开始初始化A...
开始初始化B...
初始化A完毕.
初始化B完毕.
执行业务代码...
  • await:当前线程会阻塞,直到扣除点减至0才继续运行。
  • countDown:扣除点减1,可以反复操作。

CyclicBarrier

栅栏,针对一组线程而言,只有当组内的所有线程都到达栅栏满足条件时,栅栏才会开放,组内所有线程才可以继续运行。

可以看做是:组内所有线程都持有一把钥匙,要想打开栅栏,必须集齐所有钥匙,先到达栅栏的线程会阻塞,必须等到所有线程到达才能打开栅栏。

构造器
  • 指定栅栏的线程个数
public CyclicBarrier(int parties) {
    this(parties, null);
}
  • 指定线程个数,栅栏开放后优先执行barrierAction
public CyclicBarrier(int parties, Runnable barrierAction) {
    if (parties <= 0) throw new IllegalArgumentException();
    this.parties = parties;
    this.count = parties;
    this.barrierCommand = barrierAction;
}
例子
public class CyclicBarrierDemo {
	final static int NUM = 3;
	final static CyclicBarrier BARRIER = new CyclicBarrier(NUM,()->{
		System.out.println("芝麻开门...");
	});

	static int count = 0;

	synchronized static int add(){
		return ++count;
	}

	private static class BeforeThread extends Thread{
		@Override
		public void run() {
			SleepUtil.SEC.sleep(2);
			String name = Thread.currentThread().getName();
			System.out.println(name + ":获得第" + add() + "把钥匙...");
			try {
				BARRIER.await();
				System.out.println(name + ":通行.");
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	public static void main(String[] args) {
		System.out.println("获得"+NUM+"把钥匙大门才会敞开!!!");
		for (int i = 0; i < 3; i++) {
			new BeforeThread().start();
		}
	}
}

输出如下:

获得3把钥匙大门才会敞开!!!
Thread-0:获得第1把钥匙...
Thread-1:获得第3把钥匙...
Thread-2:获得第2把钥匙...
芝麻开门...
Thread-2:通行.
Thread-1:通行.
Thread-0:通行.

CountDownLatch和CyclicBarrier的区别

尽管两者很像,但还是有本质区别。

CountDownLatch:某些代码的运行需要其他先决条件处理完毕才可执行,类似于接力赛,必须前面的人跑完了后面的人才能跑。

一个线程(或者多个), 等待另外N个线程完成某个事情之后才能执行。

CyclicBarrier:类似于团队赛,必须每个人都到达终点才算结束。

N个线程相互等待,任何一个线程完成之前,所有的线程都必须等待。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

长河0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值