Accessing output from barrier action in CyclicBarrier

184 Views Asked by At

I was practicing this question from oracle blog about happens before, i have a question in how to obtain/access the output of a barrier action in CyclicBarrier.

The blog link

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

the code

 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();
    }
  }

please let me know on how to obtain the value of the cyclic barrier action ans in the main method?

2

There are 2 best solutions below

3
zysaaa On BEST ANSWER

You can make doCalculation return result synchronously by using a additional CountDownLatch(CountDownLatch), in this case, your doCalculation method will be blocked until the calculation result is generated:

    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());
    }
0
Sree Kumar On

Since CyclicBarrier takes a Runnable only, it does not return a value. So, you will need to set the result in an externally defined output container - may be an AtomicReference as a field in CBTest. The Runnable can then set the value to it.

Here's a slightly changed version, with my changes marked with the comment 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();
    }
}