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。
內存一致性影響: -
- 線程在調用await()方法之前的行爲要優先於barrier action中的任何行爲。
-
- 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 的區別
- CountDownLatch 是計數器,只能使用一次,而 CyclicBarrier 的計數器提供 reset 功能,可以多次使用。
- 對於 CountDownLatch 來說,重點是“一個線程(多個線程)等待”,而其他的 N 個線程在完成“某件事情”之後,可以終止,也可以等待。而對於 CyclicBarrier,重點是多個線程,在任意一個線程沒有完成,所有的線程都必須等待。
- CountDownLatch 是計數器,線程完成一個記錄一個,只不過計數不是遞增而是遞減,而 CyclicBarrier 更像是一個閥門,需要所有線程都到達,閥門才能打開,然後繼續執行。
– 以上爲《JAVA多線程(十三)Java多線程之CyclicBarrier》,如有不當之處請指出,我後續逐步完善更正,大家共同提高。謝謝大家對我的關注。
——厚積薄發(yuanxw)