讀古今文學網 > 編寫高質量代碼:改善Java程序的151個建議 > 建議131:CyclicBarrier讓多線程齊步走 >

建議131:CyclicBarrier讓多線程齊步走

思考這樣一個案例:兩個工人從兩端挖掘隧道,各自獨立奮戰,中間不溝通,如果兩人在匯合點處碰頭了,則表明隧道已經挖通。這描繪的也是在多線程編程中,兩個線程獨立運行,在沒有線程間通信的情況下,如何解決兩個線程彙集在同一原點的問題。Java提供了CyclicBarrier(關卡,也有翻譯為柵欄)工具類來實現,代碼如下:


static class Worker implements Runnable{

//關卡

private CyclicBarrier cb;

public Worker(CyclicBarrier_cb){

cb=_cb;

}

public void run(){

try{

Thread.sleep(new Random().nextInt(1000));

System.out.println(Thread.currentThread().getName()+"-到達匯合點");

//到達匯合點

cb.await();

}catch(Exception e){

//異常處理

}

}

}

public static void main(Stringargs)throws Exception{

//設置彙集數量,以及彙集完成後的任務

CyclicBarrier cb=new CyclicBarrier(2,new Runnable(){

public void run(){

System.out.println("隧道已經打通!");

}

});

//工人1挖隧道

new Thread(new Worker(cb),"工人1").start();

//工人2挖隧道

new Thread(new Worker(cb),"工人2").start();

}


在這段程序中,定義了一個需要等待2個線程彙集的CyclicBarrier關卡,並且定義了完成彙集後的任務(輸出「隧道已經打通!」),然後啟動了2個線程(也就是2個工人)開始執行任務。代碼邏輯如下:

1)2個線程同時開始運行,實現不同的任務,執行時間不同。

2)「工人1」線程首先到達匯合點(也就是cb.await語句),轉變為等待狀態。

3)「工人2」線程到達匯合點,滿足預先的關卡條件(2個線程到達關卡),繼續執行。此時還會額外的執行兩個動作:執行關卡任務(也就是run方法)和喚醒「工人1」線程。

4)「工人1」線程繼續執行。

CyclicBarrier關卡可以讓所有線程全部處於等待狀態(阻塞),然後在滿足條件的情況下繼續執行,這就好比是一條起跑線,不管是如何到達起跑線的,只要到達這條起跑線就必須等待其他人員,待人員到齊後再各奔東西,CyclicBarrier關注的是匯合點的信息,而不在乎之前或之後做何處理。

CyclicBarrier可以用在系統的性能測試中,例如我們編寫了一個核心算法,但不能確定其可靠性和效率如何,我們就可以讓N個線程彙集到測試原點上,然後「一聲令下」,所有的線程都引用該算法,即可觀察出算法是否有缺陷。