亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

循環柵欄 CyclicBarrier

1.前言

本節帶領大家認識第三個常用的 Java 并發工具類之 CyclicBarrier。

本節先介紹 CyclicBarrier 工具類的表達的概念和最基本用法,接著通過一個生活中的例子為大家解釋 CyclicBarrier 工具類的使用場合,然后通過簡單的編碼實現此場景,最后帶領大家熟悉 CyclicBarrier 工具類的其他重要方法。

下面我們正式開始介紹吧。

2.概念解釋

所謂 Cyclic 即循環的意思,所謂 Barrier 即屏障的意思。所以綜合起來,CyclicBarrier 指的就是循環屏障,雖然這個叫法很奇怪,但是卻能很好地表達其含義。

CyclicBarrier 工具類允許一組線程相互等待,直到所有線程都到達一個公共的屏障點,然后這些線程一起繼續執行后繼邏輯。之所以稱之為 “循環”,是因為在所有線程都釋放了對這個屏障的使用后,這個屏障還可以重新使用。我們通過一張圖可以直觀了解其表達的控制模型。
圖片描述
現在我們已經了解了基本概念邏輯,CyclicBarrier 工具類最基本的用法是怎樣的呢?看下面。

3.基本用法

// 創建一個 CyclicBarrier 對象,初始化相互等待的線程數量
CyclicBarrier cyclicBarrier = new CyclicBarrier(線程個數);

// 線程1開始處理邏輯
...
// 線程1等待其他線程執行到屏障點
cyclicBarrier.await();
// 線程1等到了其他所有線程達到屏障點后繼續處理后繼邏輯
...

// 線程n開始處理邏輯
...
// 線程n等待其他線程執行到屏障點
cyclicBarrier.await();
// 線程n等到了其他所有線程達到屏障點后繼續處理后繼邏輯
...

是不是很簡單,CyclicBarrier 應用在哪些場合比較合適呢?下面我們給出最常用的場景說明。

4.常用場景

CyclicBarrier 最適合一個由多個線程共同協作完成任務的場合。

這樣描述很抽象,我們還是舉一個生活中的例子說明:某學習班總共 5 位同學,約定周末一起乘坐大巴出游,約定了共同的集合地點,雇傭了 1 位司機。請看下面代碼。

5.場景案例

import lombok.SneakyThrows;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;

public class CyclicBarrierTest {
    // 創建一個 Runnable 對象,用于屏障解除時處理全局邏輯,在此例子中代表大巴司機
    private static Runnable driver = new Runnable() {
        public void run() {
            System.out.println("所有同學已經集合完畢,開始啟動車輛出發。");
        }
    };

    // 創建一個 CyclicBarrier 對象,初始化為 5, 代表需要控制同步的線程個數,在此例子中代表 5 位同學
    static int threadCount = 5;
    private static CyclicBarrier cyclicBarrier = new CyclicBarrier(threadCount, driver);
    
    public static void main(String[] args) throws InterruptedException {
        // 模擬同學
        for(int i=1; i<=threadCount; i++) {
            // 模擬某個同學的動作
            new Thread(new Runnable() {
                @SneakyThrows
                public void run() {
                    System.out.println( Thread.currentThread().getName() + "已經開始出門...");
                    // 模擬同學出門趕往集合點的用時
                    try {
                        Thread.sleep(new Random().nextInt(10000));
                    } catch (Exception e) {}
                    System.out.println( Thread.currentThread().getName() + "已經到達集合點");
                    // 等待其他同學到達集合點(等待其他線程到達屏障點)
                    cyclicBarrier.await();
                }
            }, i + "號同學").start();
        }
    }
}

運行上面代碼,我們觀察一下運行結果。

1號同學準備出門...
2號同學準備出門...
3號同學準備出門...
4號同學準備出門...
5號同學準備出門...
5號同學已經到達集合點
4號同學已經到達集合點
1號同學已經到達集合點
2號同學已經到達集合點
3號同學已經到達集合點
所有同學已經集合完畢,開始啟動車輛出發。

觀察結果,和我們的預期一致。注意體會 CyclicBarrier 提供的多線程共同協作的模型。

6.其他方法介紹

除過上面代碼中使用的最基本的 await()方法之外,還有下面幾個方法大家可以了解一下。

  1. CyclicBarrier(int parties)
    相比案例中使用的 CyclicBarrier(int parties, Runnable barrierAction) 構造方法,此方法只用于控制并發線程,不做屏障點到達后的其他動作。

  2. await(long timeout, TimeUnit unit) 方法
    此方法可以設置等待的時限,當時限過后還未被喚起,則直接自行喚醒繼續執行后繼任務。

  3. getNumberWaiting() 方法
    調用此方法,可以獲得當前還在等待屏障點解除的線程數,一般用于了解整體處理進度。

7.小結

本節通過一個簡單的例子,介紹了 CyclicBarrier 相關的概念原理,使用場景和基本用法。希望大家在學習過程中,多思考勤練習,早日掌握之。