本文共 4065 字,大约阅读时间需要 13 分钟。
CyclicBarrier 是 Java 提供的一种同步工具,用于管理多线程程序中的屏障。它允许一组线程在到达屏障时被阻塞,直到最后一个线程到达屏障时,所有被屏障拦截的线程才会继续执行。
CyclicBarrier 可以让一组线程在到达屏障时被阻塞,直到最后一个线程到达屏障。所有被屏障拦截的线程只有在最后一个线程到达屏障后才会继续执行。这种机制在多线程计算数据时非常有用,例如计算结果完成后插入同步屏障,阻塞等待所有线程完成。
CyclicBarrier 位于 Java 的 java.util.concurrent 包下。线程在执行 await() 方法后会到达屏障,并等待其他线程也到达屏障。
CyclicBarrier 的构造方法主要有以下两种形式:
public CyclicBarrier(int parties) { this(parties, null);} public CyclicBarrier(int parties, Runnable barrierAction) { if (parties <= 0) throw new IllegalArgumentException(); this.parties = parties; this.count = parties; this.barrierCommand = barrierAction;} 以下是一个简单的两个线程示例,主线程和一个自定义的子线程都执行 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执行"); }} 由于 Java 多线程执行顺序由 CPU 随机调度决定,运行结果可能有以下两种情况:
假设我们有一个 Excel 文件,保存了一个用户的多个银行账户的银行消费记录。每个工作表(Sheet)对应一个银行卡的消费流水记录。我们需要统计该用户一年内的平均每日银行消费金额。
为了提高计算效率,使用多线程分别统计每个工作表的日均消费金额。所有线程完成后,通过 CyclicBarrier 同步,计算出所有账户的日均消费金额,最后得到该用户一年内的日均银行消费金额。
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(); }} getParties()返回 CyclicBarrier 拦截的线程数目。
getNumberWaiting()返回当前正在阻塞的线程数目(0 到 getParties() - 1)。
await()线程到达屏障后等待其他线程到达屏障。
reset()重置计算器,允许线程重新执行。
转载地址:http://tvll.baihongyu.com/