首页 > 编程语言 >探索并发编程:深入理解 CyclicBarrier 的原理

探索并发编程:深入理解 CyclicBarrier 的原理

时间:2024-03-16 17:32:10浏览次数:24  
标签:栅栏 同步 编程 并发 线程 CyclicBarrier 等待 所有

文章目录


前言

在多线程编程中,同步是一项关键的任务,尤其是当涉及到多个线程需要在某个共同点上同步执行时。Java 提供了丰富的并发工具来帮助开发人员实现线程之间的同步和协作。其中之一就是 CyclicBarrier(循环栅栏),这是一种非常有用的同步工具,能够让多个线程在某个共同点上同步等待,然后同时继续执行。

在本篇博客中,我们将深入探讨 CyclicBarrier 的工作原理、基本用法以及一些常见的应用场景。通过了解 CyclicBarrier,您将能够更好地利用它来优化多线程程序的设计和性能。让我们一起开始这次探索吧!


一、CyclicBarrier是什么?

CyclicBarrier,直译为“循环栅栏”,是 Java 并发编程中的一种同步工具。

循环:

CyclicBarrier 之所以被称为“循环”栅栏,是因为它具有循环使用的特性。一旦所有线程都到达栅栏点并且栅栏打开后,CyclicBarrier 将重新初始化,可以再次使用。这使得它非常适合那些需要多次同步的场景。

栅栏:

栅栏是一种用于同步线程的机制,类似于赛跑比赛中的起跑线。在 CyclicBarrier 中,所有参与线程必须在达到栅栏点之前等待,然后一起继续执行。这种同步机制确保了所有线程在某个共同点上同时进行操作,而不会出现竞争条件或数据不一致的情况。

总结:

综合起来,CyclicBarrier 是一种允许多个线程在某个共同点上同步等待,并且能够循环使用的同步工具。它提供了一种灵活而强大的机制,使得多线程程序可以更好地管理线程之间的协作和同步,从而提高程序的性能和可靠性。

二、CyclicBarrier工作原理

1.构造函数参数:

CyclicBarrier 的构造函数接受两个参数:参与线程数和栅栏动作。参与线程数表示在栅栏上等待的线程数量,而栅栏动作则是在所有线程到达栅栏时执行的操作。

2.栅栏点:

CyclicBarrier 中的栅栏点是指所有参与线程都必须等待的位置。当所有线程都到达栅栏点时,栅栏将打开,所有线程可以继续执行。

3.等待与释放:

每个线程在达到栅栏点之前都会调用 CyclicBarrier 的 await() 方法进行等待。当所有线程都调用了 await() 方法后,栅栏将打开,所有线程都可以继续执行。

4.栅栏动作:

在所有线程到达栅栏时,可以选择执行一个栅栏动作。这个动作是在构造函数中传递给 CyclicBarrier 的一个 Runnable 对象,可以用于执行一些额外的操作,比如说重置一些状态或者触发某个事件。

5.循环使用:

与 CountDownLatch 不同,CyclicBarrier 具有循环使用的特性。一旦所有线程都到达栅栏点并且栅栏打开后,CyclicBarrier 将重新初始化,可以再次使用。

三、CyclicBarrier常用重要的方法

在这里插入图片描述

四、代码实战讲解

下面这段代码会用到CyclicBarrier.await()这个核心方法,我先来为大家解释一下:

  • CyclicBarrier.await() 方法用于在线程中等待其他线程到达栅栏点。

  • 当一个线程调用 await() 方法时,它会被阻塞,直到所有参与线程都到达栅栏点。

  • 一旦所有线程都到达栅栏点,栅栏将打开,所有线程可以继续执行。

  • 在所有线程都到达栅栏点之后,await() 方法将返回,并且线程将继续执行后续的代码。

  • 如果某个线程在等待期间被中断,或者等待的线程之一遇到了异常,那么所有线程都将抛出 BrokenBarrierException 异常。

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;

public class Race {
    private static final int NUM_RUNNERS = 4;
    private static final CyclicBarrier startLine = new CyclicBarrier(NUM_RUNNERS);

    public static void main(String[] args) {
        for (int i = 0; i < NUM_RUNNERS; i++) {
            Thread runner = new Thread(new Runner("Runner " + (i + 1)));
            runner.start();
        }
    }

    static class Runner implements Runnable {
        private final String name;

        public Runner(String name) {
            this.name = name;
        }

        @Override
        public void run() {
            try {
                System.out.println(name + " 准备就绪,等待起跑信号。");
                startLine.await(); // 等待其他选手准备就绪

                System.out.println(name + " 起跑!");
                // 运动员开始比赛...

            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }
}
  • 在这个案例中,我们创建了一个 Race 类来模拟比赛。

  • 比赛中有 4 名运动员,表示为 NUM_RUNNERS。

  • 我们使用 CyclicBarrier 对象 startLine 来表示起跑线,所有运动员都将在这里等待。

  • 每个运动员都是一个线程,表示为 Runner 类。在 run() 方法中,每个运动员首先等待其他选手准备就 绪,然后一起起跑。

  • 主方法中创建了 4 个运动员线程,并启动它们。

运行效果:

在这里插入图片描述

五、CyclicBarrier对比CountDownLatch

上面讲了这么多,大家是不是觉得CyclicBarrier和CountDownLatch这两个工具好像啊,虽然 CyclicBarrier 和 CountDownLatch 都是 Java 中用于多线程编程的同步工具,但它们之间存在一些关键的区别:

1.循环使用 vs 单次使用:

CyclicBarrier 具有循环使用的特性,一旦所有线程都到达栅栏点并且栅栏打开后,它将重新初始化,可以再次使用。
CountDownLatch 则是一次性的计数器,在计数值减为 0 后就无法再次使用,除非重新创建新的 CountDownLatch 对象。

2.等待点的语义不同:

在 CyclicBarrier 中,所有参与线程必须等待在栅栏点上,直到所有线程都到达后,栅栏才会打开,所有线程一起继续执行后续操作。
而在 CountDownLatch 中,主线程或者某个特定线程需要等待其他线程执行完特定任务后才能继续执行。

3.计数方式不同:

CyclicBarrier 的计数器是线程数量,所有参与线程都要调用 await() 方法来等待,直到所有线程都到达栅栏点后,栅栏才会打开。
CountDownLatch 的计数器可以通过 countDown() 方法递减,一旦计数器减为 0,等待的线程就会被唤醒继续执行。


总结

以上就是我对 CyclicBarrier 的讲解,希望大家可以从中学习到如何利用 CyclicBarrier 实现多线程间的同步和协作。

CyclicBarrier 提供了一种简单而强大的机制,允许多个线程在达到共同点时相互等待,然后同时继续执行。通过理解其原理和用法,我们可以更好地编写并发程序,提高程序的性能和可靠性。

在实际应用中,合理地利用 CyclicBarrier 可以解决诸如并行计算、数据同步等问题,为我们的程序带来更大的灵活性和效率。希望本文能够帮助您更深入地理解并发编程中的 CyclicBarrier,并在您的编程实践中得到应用。

标签:栅栏,同步,编程,并发,线程,CyclicBarrier,等待,所有
From: https://blog.csdn.net/weixin_67589420/article/details/136718047

相关文章

  • 网络编程4 poll和epoll
    网络编程4了解多路复用IOpollintpoll(structpollfd*fds,nfds_tnfds,inttimeout);函数说明:跟select类似,监控多路IO,但poll不能跨平台.参数说明:fds:传入传出参数,实际上是一个结构体数组fds.fd:要监控的文件描述符fds.events:POLLIN---->读事件POLLOUT-......
  • 网络编程笔记目录
    网络编程笔记基础概念socket编程https://www.cnblogs.com/AndreaDO/p/18072371三次握手和四次挥手高并发服务器(多进程与多线程)https://www.cnblogs.com/AndreaDO/p/18073716selecthttps://www.cnblogs.com/AndreaDO/p/18074786poll和epollhttps://www.cnblogs.com/And......
  • 将C++模板应用于多文件编程
    C++模板在将函数应用于多文件编程时,我们通常是将函数定义放在源文件(.cpp文件)中,将函数声明放在头文件(.h文件)中,使用函数时引入(#include命令)对应的头文件即可。编译是针对单个源文件的,只要有函数声明,编译器就能知道函数调用是否正确;而将函数调用和函数定义对应起来的过程,可以延迟到......
  • 【Linux系统编程】静态库与动态库
    静态库与动态库静态库的制作和使用编写库文件源代码和头文件。将所有需要做成库的源文件生成目标文件:gcc-c{filename}.c-o{filename}.o用ar工具将要做成库的目标文件打包:arrcslib{库名}.a{filename-1}.o...{filename-n}.o将使用库的源文件与库文件一起编译:gcc{......
  • 实验1_C语言输入输出和简单程序应用编程
    task11#include<stdio.h>2#include<stdlib.h>3intmain()4{56printf("o\to\n");7printf("<H>\t<H>\n");8printf("II\tII\n");910system("pa......
  • 网络编程3 端口复用-多路IO转接select
    网络编程3端口复用-多路IO转接TCP状态转换图端口复用防止服务器重启时之前绑定的端口还未释放或者程序突然退出而系统没有释放端口。这种情况下如果设定了端口复用,则新启动的服务器进程可以直接绑定端口。如果没有设定端口复用,绑定会失败,提示ADDR已经在使用中。解决端口复用......
  • QT网络编程之获取本机网络信息
    一.概述查询一个主机的MAC地址或者IP地址是网络应用中常用到的功能,Qt提供了QHostInfo和QNetworkInterface类可以用于此类信息的查询1.QHostInfo类(显示和查找本地的信息)2.QNetworkInterface类(获得应用程序上所在主机的所有网络接口,包括子网掩码和广播地址) 推荐一个不错......
  • Python爬虫实战系列3:今日BBNews编程新闻采集
    一、分析页面打开今日BBNews网址https://news.bicido.com,下拉选择【编程】栏目1.1、分析请求F12打开开发者模式,然后点击Network后点击任意一个请求,Ctrl+F开启搜索,输入标题ApacheDoris2.1.0版本发布,开始搜索搜索结果显示直接返回的json格式,那就soeasy了,直接copycurl,......
  • KTL 一个支持C++14编辑公式的K线技术工具平台 - 第九版,数据分析工具。支持通达信日线
    K,K线,Candle蜡烛图。T,技术分析,工具平台L,公式Language语言使用c++14,Lite小巧简易。项目仓库:https://github.com/bbqz007/KTL国内仓库:https://gitee.com/bbqz007/KTL CoreAnimationforWindows: https://github.com/bbqz007/xwzqt5 一个超简单的Qt5窗口语法: https://gith......
  • 实验一c语言输入输出和简单程序应用编程
    1#include<stdio.h>2intmain()3{456printf("o\n");7printf("<H>\n");8printf("II\n");9printf("o\n");10printf("<H>\n");11......