CountDownLatch
Countdownlatch 是一个同步工具类; 用来协调多个线程之间的同步;
这个工具通常用来控制线程等待; 它可以让某一个线程等待知道倒计时结束, 在开始执行;
CountDownLatch 的两种用法:
1. 某一线程在开始运行前等待 n 个线程执行完毕; 将 CountDownLatch 的计数器初始化为 n:new CountDownLatch(n); 每当一个任务线程执行完毕, 就将计数器减 1,CountDownLatch.Countdown; 当计数器的值变为 0 时; 在 CountDownLatch 上 await()的线程就会被唤醒. 一个典型应用场景就是启动一个服务时, 主线程需要等待多个组件加载完毕;
2. 实现多个线程开始执行任务的最大并行性; 注意是并行性; 而不是并发性; 强调的是多个线程在某一时刻同时执行, 类似于赛跑; 将多个线程放到起点; 等待发令枪响; 然后同时开跑; 做法是初始化一个共享的 CountDownLatch 对象; 将其计数器初始化为 1:new CountdownLatch(1); 多个线程在开始执行任务前首先 CountDownLatch.await(), 当主线程调用 countdownl 时, 计数器变为 0; 多个线程同时被唤醒;
- package com.practice.test;
- import java.util.concurrent.CountDownLatch;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- public class CountDownLatchExample1 {
- public static final int threadCount = 550;
- public static void main(String[] args) throws InterruptedException {
- ExecutorService threadpool = Executors.newFixedThreadPool(300);
- final CountDownLatch cl = new CountDownLatch(threadCount);
- for (int i = 0; i <threadCount; i++) {
- final int threadnum = i;
- threadpool.execute(() -> {
- try {
- test(threadnum);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } finally {
- cl.countDown();
- }
- });
- }
- cl.await();
- threadpool.shutdown();
- System.out.println("finish");
- }
- public static void test(int threadnum) throws InterruptedException {
- Thread.sleep(1000);
- System.out.println("threadnum" + threadnum);
- Thread.sleep(1000);
- }
- }
3. Countdownlatch 的不足
Countdownlatch 是一次性的, 计数器的值只能在构造方法中初始化一次, 之后没有任何机制再次对其设置值, 当 CountDownLatch 使用完毕后, 他不能再次被使用
CyclicBarrier
CyclicBarrier 和 CountDownLatch 非常类似, 他也可以实现线程间的技术等待, 但是它的功能比 CountDownLatch 更加强大和复杂. 主要应用场景和 CountDownLatch 类似
CyclicBarrier 的字面意思是可循环使用的屏障, 它要做的事情是, 让一组线程到达一个屏障时被阻塞, 直到最后一个线程到达屏障时, 屏障才会开门, 所有被屏障拦截的线程才会继续干活. CyclicBarrier 默认的构造方法时 CyclicBarrier(int parties), 其参数表示屏障拦截的线程数量, 每个线程调用 await 方法告诉 CyclicBarrier 我已经到达了屏障. 然后当前线程被阻塞;
- package com.practice.test;
- import java.util.concurrent.BrokenBarrierException;
- import java.util.concurrent.CyclicBarrier;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.TimeUnit;
- import java.util.concurrent.TimeoutException;
- public class CyclicBarrierExample2 {
- private static final int threadcount = 550;
- private static final CyclicBarrier cyb = new CyclicBarrier(5);
- public static void main(String[] args) throws InterruptedException {
- ExecutorService threadpool = Executors.newFixedThreadPool(10);
- for (int i = 0; i <threadcount; i++) {
- final int num = i;
- Thread.sleep(1000);
- threadpool.execute(() -> {
- try {
- try {
- test(num);
- } catch (TimeoutException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (BrokenBarrierException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- });
- }
- threadpool.shutdown();
- }
- public static void test(int threadnum) throws InterruptedException, BrokenBarrierException, TimeoutException {
- System.out.println("threadnum" + threadnum + "is ready");
- try {
- cyb.await(2000, TimeUnit.MILLISECONDS);
- } catch (Exception e) {
- System.out.println("CyclicBarrier");
- }
- System.out.println("threadnum" + threadnum + "isFinish");
- }
- }
CyclicBarrier 的应用场景
CyclicBarrier 可以用于多线程计算数据, 最后合并结果的应用场景. 比如我们用一个 Excel 保存了用户所有银行流水, 每个 Sheet 保存每一个账户近一年的每一笔银行流水, 现在需要统计用户的日均银行流水, 先用多线程处理每个 sheet 里的银行流水, 都执行完之后, 得到每个 sheet 的日均银行流水, 最后, 使用 barrierAction 用这些线程的计算结果, 计算出整个 Excel 的日均银行流水;
CyclicBarrier(int parties,Runnable BarrierAction), 在线程到达屏障时, 优先执行 BarrierAction, 方便处理更复杂的业务场景;
- package com.practice.test;
- import java.util.concurrent.CyclicBarrier;
- public class CyclicBarrierTest {
- public static void main(String[] args) {
- CyclicBarrier cyl = new CyclicBarrier(5, () -> {
- System.out.println("线程组执行结束");
- });
- for (int i = 0; i < 5; i++) {
- new Thread(new Readnum(i, cyl)).start();
- }
- }
- static class Readnum implements Runnable {
- private int id;
- private CyclicBarrier cdl;
- public Readnum(int id, CyclicBarrier cdl) {
- super();
- this.id = id;
- this.cdl = cdl;
- }
- @Override
- public void run() {
- synchronized (this) {
- System.out.println(Thread.currentThread().getName() + "id");
- try {
- cdl.await();
- } catch (Exception e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- System.out.println(Thread.currentThread().getName() + id + "结束了");
- }
- }
- }
- }
- https://github.com/Snailclimb
- https://blog.csdn.net/tolcf/article/details/50925145?utm_source=blogxgwz0
来源: http://www.bubuko.com/infodetail-2836051.html