J.U.C之AQS-CyclicBarrier

本文深入讲解CyclicBarrier的原理及应用,CyclicBarrier是Java并发编程中的一种同步辅助类,用于多个线程间的同步,当所有线程到达指定屏障点时,所有线程将被释放并继续执行。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简单记录一下CyclicBarrier的使用

简介

  1. CyclicBarrier是一个同步辅助类,它允许一组线程相互等待直到所有线程都到达一个公共的屏障点。
  2. 在程序中有固定数量的线程,这些线程有时候必须等待彼此,这种情况下,使用CyclicBarrier很有帮助。
  3. 这个屏障之所以用循环修饰,是因为在所有的线程释放彼此之后,这个屏障是可以重新使用的。

CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier)。它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续干活。CyclicBarrier默认的构造方法是CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程调用await方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。

就像长途汽车站提供长途客运服务。当等待坐车的乘客到达20人时,汽车站就会发出一辆长途汽车,让这20个乘客上车走人。等到下次等待的乘客又到达20人是,汽车站就会又发出一辆长途汽车。
这里写图片描述

CyclicBarrier和CountDownLatch有相似点,他们都是通过计数器来实现的,但是CyclicBarrier的技术器可以重置,多次使用,CountDownLatch是等待一个或者n个线程执行完成之后做一些事,CyclicBarrier是多个线程之间相互等待,CyclicBarrier中的每一个线程执行完成之后调用await() 方法(计数器加1)进入等待,当所有线程都执行完成之后,才会继续往下执行。
下面看代码:

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CyclicBarrierTest {

    private final static int threadNum = 10;

    private static CyclicBarrier cyclicBarrier = new CyclicBarrier(5);

    public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newCachedThreadPool();  //创建一个线程池

        for(int i = 0; i < threadNum; i++){
            final int finalI = i;
            Thread.sleep(1000); //每个线程执行前睡眠1秒
            executorService.execute(() -> {
                try {
                    test(finalI);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        }
        executorService.shutdown();
    }

    private static void test(int num) throws Exception{
        Thread.sleep(1000);
        System.out.println(num + "   当前线程执行一些操作...  " + new SimpleDateFormat(" HH:mm:ss").format(new Date()));
        cyclicBarrier.await();      //执行完成 之后调用await()  表示当前自己已经执行完成
        System.out.println(num + "   5个都执行完了...  " + new SimpleDateFormat(" HH:mm:ss").format(new Date()));// 如果要输出这段话  必须是5个都执行完成  才会执行这个
    }
}

这段代码的执行结果是:

0   当前线程执行一些操作...   17:47:07
1   当前线程执行一些操作...   17:47:08
2   当前线程执行一些操作...   17:47:09
3   当前线程执行一些操作...   17:47:10
4   当前线程执行一些操作...   17:47:11
0   5个都执行完了...   17:47:11
3   5个都执行完了...   17:47:11
4   5个都执行完了...   17:47:11
2   5个都执行完了...   17:47:11
1   5个都执行完了...   17:47:11
5   当前线程执行一些操作...   17:47:12
6   当前线程执行一些操作...   17:47:13
7   当前线程执行一些操作...   17:47:14
8   当前线程执行一些操作...   17:47:15
9   当前线程执行一些操作...   17:47:16
9   5个都执行完了...   17:47:16
5   5个都执行完了...   17:47:16
6   5个都执行完了...   17:47:16
7   5个都执行完了...   17:47:16
8   5个都执行完了...   17:47:16

从上面这个可以看出来 当调用await() 的时候不足5个, 那么不会执行await() 后面的代码 ,当达到5个之后就会里面执行await() 后面的代码

cyclicBarrier还有一个用法就是当达到一个屏障点的时候,优先执行一段代码,然后再继续执行下面的,看例子:

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CyclicBarrierTest {

    private final static int threadNum = 10;

    private static CyclicBarrier cyclicBarrier = new CyclicBarrier(5, () -> {
        System.out.println("达到5个之后先执行这里的代码");
    });

    public static void main(String[] args) throws Exception {
        ExecutorService executorService = Executors.newCachedThreadPool();  //创建一个线程池

        for(int i = 0; i < threadNum; i++){
            final int finalI = i;
            Thread.sleep(1000); //每个线程执行前睡眠1秒
            executorService.execute(() -> {
                try {
                    test(finalI);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            });
        }
        executorService.shutdown();
    }

    private static void test(int num) throws Exception{
        Thread.sleep(1000);
        System.out.println(num + "   当前线程执行一些操作...  " + new SimpleDateFormat(" HH:mm:ss").format(new Date()));
        cyclicBarrier.await();      //执行完成 之后调用await()  表示当前自己已经执行完成
        System.out.println(num + "   5个都执行完了...  " + new SimpleDateFormat(" HH:mm:ss").format(new Date()));// 如果要输出这段话  必须是5个都执行完成  才会执行这个
    }
}

这段代码的输出结果是:

0   当前线程执行一些操作...   17:58:15
1   当前线程执行一些操作...   17:58:16
2   当前线程执行一些操作...   17:58:17
3   当前线程执行一些操作...   17:58:18
4   当前线程执行一些操作...   17:58:19
达到5个之后先执行这里的代码
0   5个都执行完了...   17:58:19
1   5个都执行完了...   17:58:19
2   5个都执行完了...   17:58:19
3   5个都执行完了...   17:58:19
4   5个都执行完了...   17:58:19
5   当前线程执行一些操作...   17:58:20
6   当前线程执行一些操作...   17:58:21
7   当前线程执行一些操作...   17:58:22
8   当前线程执行一些操作...   17:58:23
9   当前线程执行一些操作...   17:58:24
达到5个之后先执行这里的代码
9   5个都执行完了...   17:58:24
6   5个都执行完了...   17:58:24
5   5个都执行完了...   17:58:24
8   5个都执行完了...   17:58:24
7   5个都执行完了...   17:58:24

从输出结果就可以看出来 每次达到屏障点就先执行一段代码再继续执行。

这就是简单的CyclicBarrier使用

个人浅薄理解,欢迎补充

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值