并发编程之 CyclicBarrier
CyclicBarrier 重复栅栏,语法和 CountDownLatch 差不多。
和 CountDownLatch 区别:可以重复执行,然后构造方法可以直接提供一个阻塞的线程等待计数器为 0 的时候再执行。
CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续运行。 CyclicBarrier 默认的构造方法是 CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用 await 方法告诉 CyclicBarrier 我已经到达了屏障,然后当前线程被阻塞。
CyclicBarrier 还提供一个更高级的构造函数 CyclicBarrier(int parties,Runnable barrierAction),用于在线程到达屏障时,优先执行 barrierAction,方便处理更复杂的业务场景。
基本语法
java
//初始化一个cyclicBarrier 计数器为2
CyclicBarrier cyclicBarrier = new CyclicBarrier(2);
//阻塞 计数器不为0的时候并且会把计数器-1
cyclicBarrier.await();
示例代码
java
package com.mengweijin.learning.basic.lock;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* @author mengweijin
*/
@Slf4j
public class CyclicBarrierDemo {
public static void main(String[] args) {
CyclicBarrier cyclicBarrier = new CyclicBarrier(2,()->{
log.debug("t1 t2 end");
});
ExecutorService service = Executors.newFixedThreadPool(2);
for (int j = 0; j < 2 ; j++) {
service.submit(() -> {
log.debug("start");
try {
TimeUnit.SECONDS.sleep(1);
log.debug("working");
cyclicBarrier.await();
} catch (Exception e) {
e.printStackTrace();
}
});
service.submit(()-> {
log.debug("start");
try {
TimeUnit.SECONDS.sleep(3);
log.debug("working");
cyclicBarrier.await();
} catch (Exception e) {
e.printStackTrace();
}
});
}
service.shutdown();
}
}
CountDownLatch 和 CyclicBarrier 辨析
CountDownLatch 的计数器只能使用一次,而 CyclicBarrier 的计数器可以反复使用。
CountDownLatch.await 一般阻塞工作线程,所有的进行预备工作的线程执行 countDown,而 CyclicBarrier 通过工作线程调用 await 从而自行阻塞,直到所有工作线程达到指定屏障,再大家一起往下走。
在控制多个线程同时运行上,CountDownLatch 可以不限线程数量,而 CyclicBarrier 是固定线程数。
同时,CyclicBarrier 还可以提供一个 barrierAction,合并多线程计算结果。