博客
关于我
JAVA同步屏障CyclicBarrier
阅读量:304 次
发布时间:2019-03-03

本文共 4065 字,大约阅读时间需要 13 分钟。

CyclicBarrier 是 Java 提供的一种同步工具,用于管理多线程程序中的屏障。它允许一组线程在到达屏障时被阻塞,直到最后一个线程到达屏障时,所有被屏障拦截的线程才会继续执行。

1. 简单介绍CyclicBarrier

1.1 功能说明

CyclicBarrier 可以让一组线程在到达屏障时被阻塞,直到最后一个线程到达屏障。所有被屏障拦截的线程只有在最后一个线程到达屏障后才会继续执行。这种机制在多线程计算数据时非常有用,例如计算结果完成后插入同步屏障,阻塞等待所有线程完成。

1.2 类的位置

CyclicBarrier 位于 Java 的 java.util.concurrent 包下。线程在执行 await() 方法后会到达屏障,并等待其他线程也到达屏障。

1.3 构造方法

CyclicBarrier 的构造方法主要有以下两种形式:

  • 传递拦截线程数的参数:
  • public CyclicBarrier(int parties) {
    this(parties, null);
    }
    1. 传递拦截线程数的参数和一个执行的线程任务:
    2. public CyclicBarrier(int parties, Runnable barrierAction) {
      if (parties <= 0) throw new IllegalArgumentException();
      this.parties = parties;
      this.count = parties;
      this.barrierCommand = barrierAction;
      }

      2. 基础使用演示

      2.1 两个线程的示例

      以下是一个简单的两个线程示例,主线程和一个自定义的子线程都执行 await() 方法:

      import java.util.concurrent.BrokenBarrierException;
      import java.util.concurrent.CyclicBarrier;
      public class CyclicBarrierTest {
      private static CyclicBarrier cyclicBarrier = new CyclicBarrier(2);
      public static void main(String[] args) {
      new Thread(new Runnable() {
      @Override
      public void run() {
      try {
      cyclicBarrier.await();
      } catch (InterruptedException e) {
      e.printStackTrace();
      } catch (BrokenBarrierException e) {
      e.printStackTrace();
      }
      System.out.println("Thread执行");
      }
      }).start();
      try {
      cyclicBarrier.await();
      } catch (InterruptedException e) {
      e.printStackTrace();
      } catch (BrokenBarrierException e) {
      e.printStackTrace();
      }
      System.out.println("Main执行");
      }
      }

      2.2 执行结果

      由于 Java 多线程执行顺序由 CPU 随机调度决定,运行结果可能有以下两种情况:

    3. 主线程先于子线程到达屏障,子线程继续等待。
    4. 子线程先于主线程到达屏障,主线程继续等待。
    5. 3. 实战演练

      3.1 场景描述

      假设我们有一个 Excel 文件,保存了一个用户的多个银行账户的银行消费记录。每个工作表(Sheet)对应一个银行卡的消费流水记录。我们需要统计该用户一年内的平均每日银行消费金额。

      3.2 实现思路

      为了提高计算效率,使用多线程分别统计每个工作表的日均消费金额。所有线程完成后,通过 CyclicBarrier 同步,计算出所有账户的日均消费金额,最后得到该用户一年内的日均银行消费金额。

      3.3 可能出现的问题

    6. 如果使用单线程计算,数据量大可能导致效率低下。
    7. 如果不使用 CyclicBarrier,计算时需要等待所有工作表完成,操作不便且容易出错。
    8. 3.4 编码实现

      import java.util.Map;
      import java.util.concurrent.CyclicBarrier;
      import java.util.concurrent.Executors;
      public class BankConsumeFlow implements Runnable {
      private static final Integer CPU_NUMBER = Runtime.getRuntime().availableProcessors();
      private CyclicBarrier cyclicBarrier = new CyclicBarrier(4, this);
      private ConcurrentHashMap
      sheetCount = new ConcurrentHashMap<>();
      private void flowCount() {
      Executor executor = Executors.newFixedThreadPool(CPU_NUMBER);
      final CountDownLatch latch = new CountDownLatch(CPU_NUMBER);
      for (int i = 0; i < CPU_NUMBER; i++) {
      executor.execute(new Runnable() {
      @Override
      public void run() {
      try {
      int sheetName = Thread.currentThread().getName();
      sheetCount.put(sheetName, 100); // 模拟一个工作表的日均流水
      cyclicBarrier.await();
      latch.countDown();
      } catch (InterruptedException e) {
      e.printStackTrace();
      } catch (BrokenBarrierException e) {
      e.printStackTrace();
      }
      }
      });
      }
      try {
      latch.await();
      } catch (InterruptedException e) {
      e.printStackTrace();
      }
      int result = 0;
      for (Map.Entry
      entry : sheetCount.entrySet()) {
      result += entry.getValue();
      }
      sheetCount.put("result", result);
      System.out.println("该用户这一年的银行消费日均为:" + result + "元");
      }
      public static void main(String[] args) {
      BankConsumeFlow bankConsumeFlow = new BankConsumeFlow();
      bankConsumeFlow.flowCount();
      }
      }

      4. 关键方法总结

      4.1 getParties()

      返回 CyclicBarrier 拦截的线程数目。

      4.2 getNumberWaiting()

      返回当前正在阻塞的线程数目(0 到 getParties() - 1)。

      4.3 await()

      线程到达屏障后等待其他线程到达屏障。

      4.4 reset()

      重置计算器,允许线程重新执行。

    转载地址:http://tvll.baihongyu.com/

    你可能感兴趣的文章
    NTP配置
    查看>>
    NUC1077 Humble Numbers【数学计算+打表】
    查看>>
    NuGet Gallery 开源项目快速入门指南
    查看>>
    NuGet(微软.NET开发平台的软件包管理工具)在VisualStudio中的安装的使用
    查看>>
    nuget.org 无法加载源 https://api.nuget.org/v3/index.json 的服务索引
    查看>>
    Nuget~管理自己的包包
    查看>>
    NuGet学习笔记001---了解使用NuGet给net快速获取引用
    查看>>
    nullnullHuge Pages
    查看>>
    NullPointerException Cannot invoke setSkipOutputConversion(boolean) because functionToInvoke is null
    查看>>
    null可以转换成任意非基本类型(int/short/long/float/boolean/byte/double/char以外)
    查看>>
    Number Sequence(kmp算法)
    查看>>
    Numix Core 开源项目教程
    查看>>
    numpy
    查看>>
    Numpy 入门
    查看>>
    NumPy 库详细介绍-ChatGPT4o作答
    查看>>
    NumPy 或 Pandas:将数组类型保持为整数,同时具有 NaN 值
    查看>>
    numpy 或 scipy 有哪些可能的计算可以返回 NaN?
    查看>>
    numpy 数组 dtype 在 Windows 10 64 位机器中默认为 int32
    查看>>
    numpy 数组与矩阵的乘法理解
    查看>>
    NumPy 数组拼接方法-ChatGPT4o作答
    查看>>