并发编程常用工具类之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个线程相互等待,任何一个线程完成之前,所有的线程都必须等待。
本文深入解析了并发编程中CountDownLatch和CyclicBarrier的使用方法及应用场景。CountDownLatch适用于某些代码需等待先决条件处理完毕后执行的情况,如同接力赛。而CyclicBarrier则更像团队赛,所有线程必须到达终点才能继续,适用于N个线程相互等待的场景。
305

被折叠的 条评论
为什么被折叠?



