JAVA多線程(十三)Java多線程之CyclicBarrier

1.JAVA多線程(十三)Java多線程之CyclicBarrier

   CyclicBarrier 和 CountDownLatch 非常類似,它也可以實現線程間的技術等待,但是它的功能比 CountDownLatch 更加複雜和強大。主要應用場景和 CountDownLatch 類似。

1.1 CyclicBarrier類

   CyclicBarrier是java.util.concurrent包下面的一個工具類,字面意思是可循環使用(Cyclic)的屏障(Barrier),通過它可以實現讓一組線程到達一個屏障(也可以叫同步點)時被阻塞,直到最後一個線程到達屏障時,所有被屏障攔截的線程纔會繼續執行。

  • CyclicBarrier是一種同步機制,它可以使得一組線程在同一個障礙點進行等待。
  • CyclicBarriers 可以通過重置計數器從而重新使用。
  • CyclicBarrier支持一個可選的Runnable命令(實例化構造函數中的參數),該命令在最後一個線程到達後,但在任何線程被釋放之前被執行。這一命令在barrier處只會被執行一次,且由最後到達的線程完成。這種屏障行爲對於在任何一方繼續之前更新共享狀態都很有用。
  • all-or-none破損模型:如果一個線程因爲中斷(or執行過程的失敗,超時等)過早的離開了barrier點,那麼等待在barrier點的其他所有線程也會在同一時間因爲BrokenBarrierException或者InterruptedException異常而離開barrier。
    內存一致性影響:
    1. 線程在調用await()方法之前的行爲要優先於barrier action中的任何行爲。
    1. barrier action成功返回這一行爲要優先於所有其他等待線程await()後的行爲。

1.2 CyclicBarrier示例

package com.yuanxw.chapter13;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;

/**
 * CyclicBarrier 的字面意思是可循環使用(Cyclic)的屏障(Barrier)。
 * 它要做的事情是,讓一組線程到達一個屏障(也可以叫同步點)時被阻塞,直到最後一個線程到達屏障時,屏障纔會開門,所有被屏障攔截的線程纔會繼續幹活。
 * CyclicBarrier默認的構造方法是CyclicBarrier(int parties),其參數表示屏障攔截的線程數量,每個線程調用await方法告訴CyclicBarrier我已經到達了屏障,然後當前線程被阻塞。
 */
public class CyclicBarrierExample {

    private static volatile boolean isRunning = true;
    public static void main(String[] args) throws BrokenBarrierException, InterruptedException {
        final CyclicBarrier cyclicBarrier = new CyclicBarrier(2, new Runnable() {
            @Override
            public void run() {
                isRunning = false;
                System.out.println("任務執行結束後,回調函數!!!");
            }
        });

        /** 線程-A **/
        new Thread(()->{
            try {
                TimeUnit.SECONDS.sleep(20);
                System.out.println(String.format("線程【%s】執行完成", Thread.currentThread().getName()));
                cyclicBarrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        },"Thread-A").start();

        /** 線程-A **/
        new Thread(()->{
            try {
                TimeUnit.SECONDS.sleep(10);
                System.out.println(String.format("線程【%s】執行完成", Thread.currentThread().getName()));
                cyclicBarrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        },"Thread-B").start();

        while (isRunning) {
            System.out.println(String.format("當前正在等待數量:【%s】", cyclicBarrier.getNumberWaiting()));
            System.out.println(String.format("正在等待所需數量:【%s】 ", cyclicBarrier.getParties()));
            System.out.println(String.format("中斷或超時:【%s】", cyclicBarrier.isBroken()));
            TimeUnit.SECONDS.sleep(5);
        }
    }
}

執行結果:

當前正在等待數量:【0】
正在等待所需數量:【2】 
中斷或超時:【false】
當前正在等待數量:【0】
正在等待所需數量:【2】 
中斷或超時:【false】
線程【Thread-B】執行完成
當前正在等待數量:【1】
正在等待所需數量:【2】 
中斷或超時:【false】
當前正在等待數量:【1】
正在等待所需數量:【2】 
中斷或超時:【false】
線程【Thread-A】執行完成
任務執行結束後,回調函數!!!

1.3 CyclicBarrier 和 CountDownLatch 的區別

  1. CountDownLatch 是計數器,只能使用一次,而 CyclicBarrier 的計數器提供 reset 功能,可以多次使用。
  2. 對於 CountDownLatch 來說,重點是“一個線程(多個線程)等待”,而其他的 N 個線程在完成“某件事情”之後,可以終止,也可以等待。而對於 CyclicBarrier,重點是多個線程,在任意一個線程沒有完成,所有的線程都必須等待。
  3. CountDownLatch 是計數器,線程完成一個記錄一個,只不過計數不是遞增而是遞減,而 CyclicBarrier 更像是一個閥門,需要所有線程都到達,閥門才能打開,然後繼續執行。

    – 以上爲《JAVA多線程(十三)Java多線程之CyclicBarrier》,如有不當之處請指出,我後續逐步完善更正,大家共同提高。謝謝大家對我的關注。

——厚積薄發(yuanxw)

發佈了125 篇原創文章 · 獲贊 166 · 訪問量 47萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章