0

我在 oracle 博客上练习了这个关于之前发生的问题,我有一个问题是如何在 CyclicBarrier 中获取/访问屏障动作的输出。

博客链接

https://blogs.oracle.com/javamagazine/post/quiz-yourself-happens-before-thread-synchronization-in-java-with-cyclicbarrier

编码

 public class CBTest {

    private List<Integer> results = Collections.synchronizedList(new ArrayList<>());
    
    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) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }

    void doCalculation() {
        CyclicBarrier cb = new CyclicBarrier(2, () -> {
            var ans = results.stream().mapToInt(v -> v.intValue()).sum();
            System.out.println("ANS IS "+ans);
            });
        new Calculator(cb, 2).start();
        new Calculator(cb, 3).start();
    }


    public static void main(String[] args) {
        var test = new CBTest();
        test.doCalculation();
    }
  }

请告诉我如何获得ansmain方法中循环障碍动作的值?

4

2 回答 2

2

您可以doCalculation使用附加的CountDownLatchCountDownLatch)同步返回结果,在这种情况下,您的doCalculation方法将被阻塞,直到生成计算结果:

    CountDownLatch countDownLatch = new CountDownLatch(1);

    int doCalculation() throws InterruptedException {
        AtomicInteger result = new AtomicInteger();
        CyclicBarrier cb = new CyclicBarrier(2, () -> {
            result.set(results.stream().mapToInt(v -> v.intValue()).sum());
            // count down
            countDownLatch.countDown();
        });
        new Calculator(cb, 2).start();
        new Calculator(cb, 3).start();
        // block util it is countDown.
        countDownLatch.await();
        return result.get();
    }

    public static void main(String[] args) throws InterruptedException {
        var test = new CBTest();
        System.out.println("ANS IS " + test.doCalculation());
    }
于 2021-11-25T00:48:44.217 回答
1

由于只CyclicBarrier接受一个Runnable,它不会返回一个值。因此,您需要将结果设置在外部定义的输出容器中 - 可能AtomicReferenceCBTest. 然后Runnable可以将值设置为它。

这是一个稍有改动的版本,我的改动用注释标记CHANGE

public class CBTest{
    private List<Integer> results = Collections.synchronizedList( new ArrayList<>() );

    /* CHANGE: Value holder. Could be another thread-safe class. */
    private AtomicReference<Integer> answer = new AtomicReference<>( 0 );

    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();
                
                /* CHANGE: Both threads get the same value. */
                System.out.println( answer.get() );
            }
            catch( InterruptedException | BrokenBarrierException e ){
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }

    void doCalculation(){
        CyclicBarrier cb = new CyclicBarrier( 2, () -> {
            var ans = results.stream().mapToInt( v -> v.intValue() ).sum();
            System.out.println( "ANS IS " + ans );
            
            /* CHANGE: Set the value here. */
            answer.set( ans );
        } );
        new Calculator( cb, 2 ).start();
        new Calculator( cb, 3 ).start();
    }

    public static void main( String[] args ){
        var test = new CBTest();
        test.doCalculation();
    }
}
于 2021-11-24T17:11:41.743 回答