Java併發——同步屏障

1.同步屏障

同步屏障允許一組線程彼此相互等待,直到抵達某個公共的屏障點。它要做的事情是,讓一組線程到達一個屏障(也可以叫同步點)時被阻塞,直到最後一個線程到達屏障時,屏障纔會開門,所有被屏障攔截的線程纔會繼續幹活。

舉個簡單的例子就是:旅遊團帶着一幫人蔘觀景點,規定在下一個景點A處集合,於是導遊就在景點A等着大家,導遊就是這個集合點或者說屏障,直到所有的遊客集合完畢,導遊纔會帶着大家繼續參觀下一個景點B.

類java.util.concurrent.CyclicBarrier實現了同步屏障。

2. 同步屏障適用場景

CyclicBarrier可以用於多線程計算數據,最後合併計算結果的場景。 

3.常用方法

(1)CyclicBarrier(int parties)構造函數

初始化一個包含指定parties數目的CyclicBarrier實例。如果parties的值小於1,構造函數就會拋出IllegalArgumentException。

(2)CyclicBarrier(int parties, Runnable barrierAction)構造函數

初始化一個包含指定parties數目的線程以及一旦跨越屏障就會執行的barrierAction. 也就是說當最後一個線程到達一個屏障點時,就會馬上執行barrierAction. 這個Runnable適用於在任意線程繼續執行之前更新共享狀態

如果parties的值小於1,構造函數就會拋出IllegalArgumentException。若把barrierAction設爲null,那麼當跨越屏障時,就沒有runnable可供執行。

(3)int await()

每個線程調用await(),表示我已經到達屏障點,然後當前線程被阻塞。如果調用線程是最後一條到達的線程,並且構造函數中提供了一個非空的barrierAction,這條線程就會在允許其他線程繼續執行之前率先執行這個runnable。該方法會返回調用線程的到達索引,getParties-1代表第一條到達的線程,0代表最後一條到達的線程。

(4)int await(long timeout, TimeUnit unit)

指定調用線程願意等待的時長,其他的跟上一個方法相同。當線程在等待中超時,該方法會拋出java.util.concurrent.TimeoutException。

(5)int getNumberWaiting()

返回當前在同步屏障上等待的線程數目。

(6)int getParties()

返回需要跨越同步屏障的線程數目。

(7)boolean isBroken()

當一條或多條線程由於在同步屏障創建或上次重置之後,中斷或超時從而打破同步屏障,又或者因爲一個異常導致barrier action失敗時,返回true;否則返回false。

(8)void reset()

把同步屏障重置到其原始狀態。

4.示例

import java.util.Random;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class CyclicBarrierTest {

	public static void main(String[] args)
	{
		CyclicBarrier barrier = new CyclicBarrier(3);
		Runnable r = new Runnable() {
			@Override
			public void run()
			{
				try {
					Thread.sleep(new Random().nextInt(10000));
					String name = Thread.currentThread().getName();
					System.out.println(name + "即將到達,當前已有"+(barrier.getNumberWaiting()+1)+"條線程已經到達!"+(barrier.getNumberWaiting()==2?"都到齊了,繼續走":"正在等待"));
					barrier.await();
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (BrokenBarrierException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		};
		
		ExecutorService executorService = Executors.newCachedThreadPool();
		for(int i = 0; i < 3; i++)
		{
			executorService.submit(r);
		}
		executorService.shutdown();
	}
}

 運行結果:

pool-1-thread-1即將到達,當前已有1條線程已經到達!正在等待
pool-1-thread-2即將到達,當前已有2條線程已經到達!正在等待
pool-1-thread-3即將到達,當前已有3條線程已經到達!都到齊了,繼續走

5. CountDownLatch與CountDownLatch的比較

    (1)CountDownLatch是把主幹線程掛起,在任務線程中進行倒數計數,直到任務線程執行完才喚醒主幹線程繼續執行;

             CyclicBarrier是把任務線程掛起,直到所有任務線程執行到屏障處再放行繼續執行;

    (2)CountDownLatch達到屏障放行標準後放行的是主幹線程;

             CyclicBarrier達到屏障放行標準後放行的是任務線程,並且還會額外地觸發一個達到標準後執行的響應線程;

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章