This is the 18th day of my participation in the August Genwen Challenge.More challenges in August

CyclicBarrier

CyclicBarrier literally means CyclicBarrier. What it does is allow a group of threads to block when they reach a barrier (also known as a synchronization point), and the barrier will not open until the last thread reaches the barrier, and all threads blocked by the barrier will continue to run.

The CyclicBarrier’s default constructor is CyclicBarrier (int parties), whose argument is the number of threads that the barrier intercepts, and each thread calls the await method to tell the CyclicBarrier that I have reached the barrier and the current thread is blocked.

public class CyclicBarrierTest {
    static CyclicBarrier c = new CyclicBarrier(2);
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run(a) {
                try {
                    c.await();
                } catch (Exception e) {
                }
                System.out.println(1);
            }
        }).start();
        try {
            c.await();
        } catch (Exception e) {
        }
        System.out.println(2); }}Copy the code

Since the scheduling of the primary and child threads is determined by the CPU, both threads may execute first, resulting in two outputs, 12 and 21

If you change new CyclicBarrier(2) to new CyclicBarrier(3), the main thread and child threads will wait forever because there is no third thread to execute the await method, that is, no third thread has reached the barrier, so neither of the two threads that reached the barrier before will continue to execute.

CyclicBarrier also provides a more advanced constructor CyclicBarrier (int parties, Runnable barrierAction) that takes precedence over barrierAction when a thread reaches a barrier, facilitating more complex business scenarios

public class CyclicBarrierTest2 {
    static CyclicBarrier c = new CyclicBarrier(2.new A());

    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run(a) {
                try {
                    c.await();
                } catch (Exception e) {
                }
                System.out.println(1);
            }
        }).start();
        try {
            c.await();
        } catch (Exception e) {
        }
        System.out.println(2);
    }

    static class A implements Runnable {
        @Override
        public void run(a) {
            System.out.println(3); }}}Copy the code

Because CyclicBarrier sets the number of intercepting threads to 2, the main thread must wait until the first thread in the code and thread A have finished executing, and then 312 is printed

public class BankWaterService implements Runnable {
    /** * Create four barriers and execute the run method of the current class */ after processing
    private CyclicBarrier c = new CyclicBarrier(4.this);
    /** * assume only four sheets, so only four threads are started */
    private Executor executor = Executors.newFixedThreadPool(4);
    /** * Saves the silver flow results calculated by each sheet */
    private ConcurrentHashMap<String, Integer> sheetBankWaterCount = new
            ConcurrentHashMap<String, Integer>();

    private void count(a) {
        for (int i = 0; i < 4; i++) {
            executor.execute(new Runnable() {
                @Override
                public void run(a) {
				// Calculate the current sheet silver flow data, calculation code omitted
                    sheetBankWaterCount
                            .put(Thread.currentThread().getName(), 1);
				// The silver flow is calculated and a barrier is inserted
                    try {
                        c.await();
                    } catch(Exception e) { e.printStackTrace(); }}}); }}@Override
    public void run(a) {
        int result = 0;
        // Summarize the results calculated by each sheet
        for (Map.Entry<String, Integer> sheet : sheetBankWaterCount.entrySet()) {
            result += sheet.getValue();
        }
// Print the result
        sheetBankWaterCount.put("result", result);
        System.out.println(result);
    }

    public static void main(String[] args) {
        BankWaterService bankWaterCount = newBankWaterService(); bankWaterCount.count(); }}Copy the code

Create 4 threads using the thread pool, calculate the data in each sheet, calculate the result of each sheet 1, then the BankWaterService thread summarize the result of 4 sheets, output the result of 4

CountDownLatch’s counter can only be used once, while CyclicBarrier’s counter can be reset using the reset() method. So CyclicBarrier can handle more complex business scenarios. For example, if a calculation error occurs, you can reset the counter and have the thread execute again.

CyclicBarrier also provides other useful methods, such as the getNumberWaiting method that gets the number of threads blocked by CyclicBarrier. The isBroken() method is used to know if a blocking thread is interrupted

public class CyclicBarrierTest3 {
    static CyclicBarrier c = new CyclicBarrier(2);
    public static void main(String[] args) throws InterruptedException, BrokenBarrierException {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run(a) {
                try {
                    c.await();
                } catch (Exception e) {
                }
            }
        });
        thread.start();
        thread.interrupt();
        try {
            c.await();
        } catch(Exception e) { System.out.println(c.isBroken()); }}}Copy the code