1. 程式人生 > >二、Java多執行緒併發同步之CyclicBarrier

二、Java多執行緒併發同步之CyclicBarrier

概述

CyclicBarrier:可迴圈屏障,允許一組執行緒全部等待的同步輔助工具。一組執行緒互相等待,直到所有執行緒都到達某個公共屏障點(也可以叫同步點) 。它可以在等待執行緒之後重新使用。這個屏障之所以用迴圈修飾,是因為在所有的執行緒釋放彼此之後,這個屏障是可以重新使用的 。

CyclicBarrier支援一個可選的Runnable命令,在一組執行緒中的最後一個執行緒到達屏障點之後(但在釋放所有執行緒之前),該命令只在所有執行緒到達屏障點之後執行一次,並且該命令由最後一個進入屏障點的執行緒執行。

業務場景

需要所有的子任務都完成時,才執行主任務,這個時候就可以選擇使用CyclicBarrier。 例如,多執行緒計算資料,最後合併彙總計算的場景;長途汽車等人到齊了才發車的場景,王者榮耀5V5時,需要10個人的進度都為100%時才能進入遊戲等等場景都可以使用CyclicBarrier實現。

下面介紹一個5個人約好去五星級大酒店聚餐場景:5個人約好去聚餐,由於每個人家到酒店的距離不一樣,所以需要等所有人到齊後,才能開餐吃飯,並且規定誰最後一個到,就請大家一起去按摩,然後去吃飯。

實現

CyclicBarrier(int parties):建立一個給定數量執行緒的迴圈屏障,當到達同步點時,不執行預先定義的動作

CyclicBarrier(int parties, Runnable barrierAction):建立一個給定數量執行緒的迴圈屏障,當到達同步點時,執行 Runnable方法

await():進行阻塞等待 ,直到滿足下列條件時,繼續執行:

  • 等待的執行緒數達到parties時,所有到達的執行緒將被釋放,繼續向下執行。
  • 當前執行緒被中斷,丟擲InterruptedException異常,並停止等待,繼續執行。
  • 其他等待的執行緒被中斷(interrupt),當前執行緒會丟擲BrokenBarrierException異常,並停止等待,繼續執行。
  • 其他等待的執行緒超時,當前執行緒會丟擲BrokenBarrierException異常,並停止等待,繼續執行。
  • 其他執行緒呼叫reset()方法,當前執行緒會丟擲BrokenBarrierException異常,並停止等待,繼續執行。

reset():重置,使CyclicBarrier迴歸初始狀態

getNumberWaiting():獲取正在等待的執行緒數量。

/**
 * CyclicBarrier : 可迴圈的屏障,讓一組執行緒到達一個同步點後再一起繼續執行,在其中任意一個執行緒未達到同步點,其他到達的執行緒均會被阻塞。
 * 業務場景: 5個人約好去五星級大酒店聚餐
 */
public class CyclicBarrierTest implements Runnable {
	private ExecutorService es = Executors.newCachedThreadPool();
	private CyclicBarrier cyclicBarrier = new CyclicBarrier(5, this); // 攔截執行緒為5

	//達到同步點後執行方法
	@Override
	public void run() {
		System.out.println("吃飯前先一起去按摩");
	}

	//實現任務
	public void invoke() {
		// 5個執行緒,模擬5個人
		for (int i = 0; i < 5; i++) {
			final String user = "user"+(i+1);
			es.execute(new Runnable() {
				@Override
				public void run() {
					try {
						Thread.sleep((long)(Math.random()*10000));   //模擬去酒店,每個人都不一樣
						System.out.println(user+"---到達酒店,當前有"+(cyclicBarrier.getNumberWaiting()+1)+"個人到達");
						
						cyclicBarrier.await(); // 等待所有人到酒店
						
						System.out.println(user + "---所有人到齊,吃飯去了。。。");
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			});
		}
	}

	public static void main(String[] args) {
		CyclicBarrierTest service = new CyclicBarrierTest();
		service.invoke();
	}
}

輸出結果:

user4---到達酒店,當前有1個人到達
user2---到達酒店,當前有2個人到達
user3---到達酒店,當前有3個人到達
user1---到達酒店,當前有4個人到達
user5---到達酒店,當前有5個人到達
吃飯前先一起去按摩
user5---所有人到齊,吃飯去了。。。
user4---所有人到齊,吃飯去了。。。
user1---所有人到齊,吃飯去了。。。
user3---所有人到齊,吃飯去了。。。
user2---所有人到齊,吃飯去了。。。