CyclicBarrier循環(huán)屏障(障礙),同樣都是jdk線程并發(fā)包下的java.util.concurrent,底層使用ReentrantLock可重入鎖,共享資源重復加鎖,該線程獲取鎖不被阻塞。
使用場景:約好4個人一起打麻將,如果是三缺一就無法進行,三個人需要等待1人,四個人達到麻將館即可開戰(zhàn)。
或者處理間斷,反復請求時,避免一條條的處理,定義規(guī)則滿足10次提交一次業(yè)務流,當不滿足10次,一直阻塞等待。
/**
* CyclicBarrier 循環(huán)屏障
* jdk:"一種同步幫助,允許一組線程等待所有線程,互相達到一個共同的障礙點",大白話講:滿足n個線程數(shù)量,才能訪問后續(xù)動作,不滿足就一直等待。
*/
public class CyclicBarrierTest {
public static final Logger logger = LoggerFactory.getLogger(CyclicBarrierTest.class);
public static void main(String[] args) {
/**
* Creates a new {@code CyclicBarrier} that will trip when the
* given number of parties (threads) are waiting upon it, and
* does not perform a predefined action when the barrier is tripped.
*
* @param parties the number of threads that must invoke {@link #await}
* before the barrier is tripped
* @throws IllegalArgumentException if {@code parties} is less than 1
*/
//定義5個循環(huán)障礙,5個線程執(zhí)行完后,會解除阻塞,計數(shù)清零。然后循環(huán)重復此規(guī)則
CyclicBarrier cyclicBarrier = new CyclicBarrier(5);
//定義一個緩存線程池,如果有空閑的線程進行回收,否則創(chuàng)建新的線程
ExecutorService executors = Executors.newCachedThreadPool();
//這里可以模擬不同的請求數(shù)來驗證,第一次可以循環(huán)5次,第二次循環(huán)6次,第三次循環(huán)10次,來觀察不同之處
//循環(huán)5次,剛好一組任務完成。
//循環(huán)6次,只能滿足第一組任務,第二組任務將一直等待,阻塞任務。
//循環(huán)十次,兩組任務都可以完成。
for (int i = 0; i < 10; i++) {
executors.execute(() -> {
logger.info(Thread.currentThread().getName() + "進入考場");
try {
//dowait方法ReentrantLock 可重入鎖
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
logger.info(Thread.currentThread().getName() + "開始考試...");
});
}
executors.shutdown();
}
}
日中輸出:
18:05:19.283 [pool-1-thread-3] INFO com.test.tenant.CyclicBarrierTest - pool-1-thread-3進入考場
18:05:19.283 [pool-1-thread-4] INFO com.test.tenant.CyclicBarrierTest - pool-1-thread-4進入考場
18:05:19.283 [pool-1-thread-5] INFO com.test.tenant.CyclicBarrierTest - pool-1-thread-5進入考場
18:05:19.283 [pool-1-thread-1] INFO com.test.tenant.CyclicBarrierTest - pool-1-thread-1進入考場
18:05:19.283 [pool-1-thread-2] INFO com.test.tenant.CyclicBarrierTest - pool-1-thread-2進入考場
18:05:19.286 [pool-1-thread-3] INFO com.test.tenant.CyclicBarrierTest - pool-1-thread-3開始考試...
18:05:19.286 [pool-1-thread-5] INFO com.test.tenant.CyclicBarrierTest - pool-1-thread-5開始考試...
18:05:19.286 [pool-1-thread-4] INFO com.test.tenant.CyclicBarrierTest - pool-1-thread-4開始考試...
18:05:19.286 [pool-1-thread-2] INFO com.test.tenant.CyclicBarrierTest - pool-1-thread-2開始考試...
18:05:19.286 [pool-1-thread-1] INFO com.test.tenant.CyclicBarrierTest - pool-1-thread-1開始考試...
CyclicBarrier 和CountDownLatch區(qū)別:
阻塞區(qū)別:
CountDownLatch某一個或多個線程 ,等待其他線程執(zhí)行完成之后,才能繼續(xù)執(zhí)行。父線程等待子線程執(zhí)行完成,才能繼續(xù)執(zhí)行。
CyclicBarrier 一組線程互相等待,任何一個未執(zhí)行完成,其他線程都需要等待。10個線程,全部完成,才能執(zhí)行后續(xù)動作。
使用次數(shù)區(qū)別:
CountDownLatch倒計時門閂,每執(zhí)行一次都是遞減1,await等于0時,結束阻塞,不可重復使用
CyclicBarrier循環(huán)屏障,每執(zhí)行一次都是遞加1,barrier釋放完后,可繼續(xù)使用,重復循環(huán)使用。
鎖區(qū)別
CountDownLatch 內(nèi)部使用 Sync AQS 狀態(tài)來控制,volatile可見性控制線程間變量共享
CyclicBarrier內(nèi)部使用ReentrantLock可重入鎖