如何在main方法中获取CyclicBarrier屏障动作的输出结果
实现方案
你需要同时解决两个核心问题:
- 将屏障动作中计算的
ans存储到可被main方法访问的共享位置 - 保证
main方法读取值时,屏障动作已经完成计算,符合Java的happens-before可见性规则
具体修改步骤
- 给
CBTest类新增一个volatile修饰的成员变量,用于存储计算结果,保证多线程下的可见性 - 在屏障动作中把计算得到的
ans赋值给这个成员变量 - 让
main线程等待所有计算线程执行完成后,再读取这个成员变量的值
修改后完整代码
import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.concurrent.CyclicBarrier; public class CBTest { private List<Integer> results = Collections.synchronizedList(new ArrayList<>()); // 新增volatile修饰的成员变量存储结果,保证可见性 private volatile int sumResult; class Calculator extends Thread { CyclicBarrier cb; int param; public Calculator(CyclicBarrier cb, int param) { this.cb = cb; this.param = param; } public void run() { try { results.add(param); System.out.println("going to await"); cb.await(); } catch (InterruptedException | BrokenBarrierException e) { e.printStackTrace(); } } } // 方法修改为返回两个计算线程的实例,供main调用join等待 Calculator[] doCalculation() { CyclicBarrier cb = new CyclicBarrier(2, () -> { var ans = results.stream().mapToInt(v -> v.intValue()).sum(); System.out.println("ANS IS " + ans); // 把计算结果赋值给成员变量 sumResult = ans; }); Calculator t1 = new Calculator(cb, 2); Calculator t2 = new Calculator(cb, 3); t1.start(); t2.start(); return new Calculator[]{t1, t2}; } public static void main(String[] args) throws InterruptedException { var test = new CBTest(); Calculator[] threads = test.doCalculation(); // 等待两个计算线程全部执行完成,此时屏障动作已经执行完毕 for (Calculator t : threads) { t.join(); } // 直接读取结果即可 int ansFromBarrier = test.sumResult; System.out.println("main方法拿到的结果:" + ansFromBarrier); } }
原理说明
根据CyclicBarrier的happens-before规则:
- 所有线程中
await()调用之前的操作,都优先于屏障动作中的操作执行 - 屏障动作中的所有操作,都优先于所有线程从
await()返回之后的操作执行
所以当main通过join等待两个计算线程全部执行完成后,读取到的sumResult一定是屏障动作计算完成后的正确值,不存在可见性问题。
内容的提问来源于stack exchange,提问作者Umar
相关产品推荐
相关产品推荐

