目錄
一、AQS
組件CyclicBarrier
1.CyclicBarrier
介紹
CyclicBarrier
跟AQS
其他組件,也是一個同步輔助類,它允許一組線程相互等待,直到到達某個公共的屏障點(循環屏障)CyclicBarrier
可以完成多個線程之間相互等待,只有每個線程都準備就緒後才能繼續往下執行後面的操作。- 每當有一個線程執行了
await
方法,計數器就會執行+1操作,待計數器達到預定的值,所有的線程再同時繼續執行。由於計數器釋放之後可以重用(reset
方法),所以稱之爲循環屏障。
2.CyclicBarrier
與CountDownLatch
的區別
CountDownLatch
只有一個計數器,且不可重複使用;CyclicBarrier
的計數器可以重複使用;CountDownLatch
描述的是一個或多個線程等待其他線程的關係;CyclicBarrier
描述的是多個線程相互等待的關係,直到所有線程都滿足了條件才繼續執行後續的操作;
二、CyclicBarrier
的應用
1. await()
允許一組線程相互等待,直到到達某個公共的屏障點。
await()
方法源碼:
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
情景:
線程池中10個,每次線程執行了輸出ready
日誌操作後,進入等待狀態,直到有5
個線程都執行了輸出ready
日誌操作,才允許執行後續輸出contunie
日誌操作,循環往復。示例代碼如下:
@Slf4j
public class CyclicBarrierExample1 {
//實例化一個CyclicBarrier,並初始化屏障數爲5;
private static CyclicBarrier barrier = new CyclicBarrier(5);
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i=0; i<10; i++){
final int threadNum = i;
//此處爲了便於觀察,讓每個線程間隔1秒
Thread.sleep(1000);
executorService.execute(()->{
try {
race(threadNum);
} catch (Exception e) {
e.printStackTrace();
}
});
}
executorService.shutdown();
}
private static void race(int threadNum) throws Exception{
Thread.sleep(1000);
log.info("{} is ready",threadNum);
//線程進入等待的狀態,直至等待線程數滿足CyclicBarrier 初始化的5
barrier.await();
log.info("{} is continue",threadNum);
}
}
執行結果如下:
10:03:32.886 [pool-1-thread-1] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample1 - 0 is ready
10:03:33.801 [pool-1-thread-2] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample1 - 1 is ready
10:03:34.778 [pool-1-thread-3] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample1 - 2 is ready
10:03:35.778 [pool-1-thread-4] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample1 - 3 is ready
10:03:36.778 [pool-1-thread-5] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample1 - 4 is ready
10:03:36.778 [pool-1-thread-5] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample1 - 4 is continue
10:03:36.778 [pool-1-thread-4] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample1 - 3 is continue
10:03:36.778 [pool-1-thread-3] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample1 - 2 is continue
10:03:36.778 [pool-1-thread-2] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample1 - 1 is continue
10:03:36.778 [pool-1-thread-1] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample1 - 0 is continue
10:03:37.780 [pool-1-thread-6] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample1 - 5 is ready
10:03:38.780 [pool-1-thread-2] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample1 - 6 is ready
10:03:39.780 [pool-1-thread-5] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample1 - 7 is ready
10:03:40.780 [pool-1-thread-1] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample1 - 8 is ready
10:03:41.780 [pool-1-thread-4] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample1 - 9 is ready
10:03:41.780 [pool-1-thread-6] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample1 - 5 is continue
10:03:41.780 [pool-1-thread-2] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample1 - 6 is continue
10:03:41.780 [pool-1-thread-4] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample1 - 9 is continue
10:03:41.780 [pool-1-thread-1] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample1 - 8 is continue
10:03:41.780 [pool-1-thread-5] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample1 - 7 is continue
Process finished with exit code 1
執行的結果與預期的一致。
2. await(long timeout, TimeUnit unit)
設置超時時間,若該等待超過了設定值,該線程將不會繼續等待,而是繼續執行
await(long timeout, TimeUnit unit)
方法源碼如下:
public int await(long timeout, TimeUnit unit)
throws InterruptedException,
BrokenBarrierException,
TimeoutException {
return dowait(true, unit.toNanos(timeout));
}
BrokenBarrierException
解讀:已經進入等待狀態的線程,由於等待時間達到了超時時間,該線程將不再繼續等待,因此CyclicBarrier
維護的線程等待隊列的狀態突然發生了改變,所有會拋出異常;
情景:
線程池中10個,每次線程執行了輸出ready
日誌操作後,進入等待狀態,直到有5
個線程都執行了輸出ready
日誌操作,才允許執行後續輸出contunie
日誌操作,但是如果等待時間超過了2
秒,則該線程將不必等待,直接繼續執行。循環往復。示例代碼如下:
@Slf4j
public class CyclicBarrierExample2 {
//實例化一個CyclicBarrier,並初始化屏障數爲5;
private static CyclicBarrier barrier = new CyclicBarrier(5);
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i=0; i<10; i++){
final int threadNum = i;
Thread.sleep(1000);
executorService.execute(()->{
try {
race(threadNum);
} catch (Exception e) {
e.printStackTrace();
}
});
}
executorService.shutdown();
}
private static void race(int threadNum) throws Exception{
Thread.sleep(1000);
log.info("{} is ready",threadNum);
try {
//設置超時時間,若該等待超過了設定值,該線程將不會繼續等待,而是繼續執行
barrier.await(2000, TimeUnit.MILLISECONDS);
}catch (Exception e){
log.warn("Exception:{}" ,e.getMessage());
}
log.info("{} is continue",threadNum);
}
}
執行結果如下:
10:37:57.310 [pool-1-thread-1] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample2 - 0 is ready
10:37:58.310 [pool-1-thread-2] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample2 - 1 is ready
10:37:59.309 [pool-1-thread-3] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample2 - 2 is ready
10:37:59.319 [pool-1-thread-1] WARN com.mmall.concurrency.example.aqs.CyclicBarrierExample2 - Exception:null
10:37:59.320 [pool-1-thread-2] WARN com.mmall.concurrency.example.aqs.CyclicBarrierExample2 - Exception:null
10:37:59.320 [pool-1-thread-3] WARN com.mmall.concurrency.example.aqs.CyclicBarrierExample2 - Exception:null
10:37:59.321 [pool-1-thread-2] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample2 - 1 is continue
10:37:59.321 [pool-1-thread-3] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample2 - 2 is continue
10:37:59.320 [pool-1-thread-1] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample2 - 0 is continue
10:38:00.310 [pool-1-thread-4] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample2 - 3 is ready
10:38:00.311 [pool-1-thread-4] WARN com.mmall.concurrency.example.aqs.CyclicBarrierExample2 - Exception:null
10:38:00.311 [pool-1-thread-4] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample2 - 3 is continue
10:38:01.310 [pool-1-thread-1] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample2 - 4 is ready
10:38:01.310 [pool-1-thread-1] WARN com.mmall.concurrency.example.aqs.CyclicBarrierExample2 - Exception:null
10:38:01.310 [pool-1-thread-1] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample2 - 4 is continue
10:38:02.310 [pool-1-thread-4] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample2 - 5 is ready
10:38:02.310 [pool-1-thread-4] WARN com.mmall.concurrency.example.aqs.CyclicBarrierExample2 - Exception:null
10:38:02.310 [pool-1-thread-4] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample2 - 5 is continue
10:38:03.311 [pool-1-thread-1] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample2 - 6 is ready
10:38:03.311 [pool-1-thread-1] WARN com.mmall.concurrency.example.aqs.CyclicBarrierExample2 - Exception:null
10:38:03.311 [pool-1-thread-1] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample2 - 6 is continue
10:38:04.311 [pool-1-thread-1] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample2 - 7 is ready
10:38:04.311 [pool-1-thread-1] WARN com.mmall.concurrency.example.aqs.CyclicBarrierExample2 - Exception:null
10:38:04.311 [pool-1-thread-1] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample2 - 7 is continue
10:38:05.311 [pool-1-thread-4] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample2 - 8 is ready
10:38:05.311 [pool-1-thread-4] WARN com.mmall.concurrency.example.aqs.CyclicBarrierExample2 - Exception:null
10:38:05.311 [pool-1-thread-4] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample2 - 8 is continue
10:38:06.312 [pool-1-thread-1] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample2 - 9 is ready
10:38:06.312 [pool-1-thread-1] WARN com.mmall.concurrency.example.aqs.CyclicBarrierExample2 - Exception:null
10:38:06.312 [pool-1-thread-1] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample2 - 9 is continue
Process finished with exit code 1
3.new CyclicBarrier(int parties, Runnable barrierAction);
CyclicBarrier
在實例化的時候,可以設置一個優先線程。當線程等待數達到屏障值,則優先執行此優先線程;
CyclicBarrier(int parties, Runnable barrierAction)
構造方法源碼
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}
情景:
線程池中10個,每次線程執行了輸出ready
日誌操作後,進入等待狀態。當有5
個線程都執行了輸出ready
日誌操作,首先執行優先線程來打印“當線程等待數達到設定值,優先執行此線程”內容,然後所有等待的線程才允許執行後續輸出contunie
日誌操作,循環往復。示例代碼如下:
@Slf4j
public class CyclicBarrierExample3 {
//實例化一個CyclicBarrier,並初始化屏障數爲5;
private static CyclicBarrier barrier = new CyclicBarrier(5,()->{
log.info("當線程等待數達到設定值,優先執行此線程");
});
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
for (int i=0; i<10; i++){
final int threadNum = i;
Thread.sleep(1000);
executorService.execute(()->{
try {
race(threadNum);
} catch (Exception e) {
e.printStackTrace();
}
});
}
executorService.shutdown();
}
private static void race(int threadNum) throws Exception{
Thread.sleep(1000);
log.info("{} is ready",threadNum);
barrier.await();
log.info("{} is continue",threadNum);
}
}
輸出結果如下:
10:49:19.972 [pool-1-thread-1] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample3 - 0 is ready
10:49:20.968 [pool-1-thread-2] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample3 - 1 is ready
10:49:21.973 [pool-1-thread-3] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample3 - 2 is ready
10:49:23.001 [pool-1-thread-4] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample3 - 3 is ready
10:49:23.971 [pool-1-thread-5] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample3 - 4 is ready
10:49:23.971 [pool-1-thread-5] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample3 - 當線程等待數達到設定值,優先執行此線程
10:49:23.971 [pool-1-thread-5] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample3 - 4 is continue
10:49:23.971 [pool-1-thread-1] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample3 - 0 is continue
10:49:23.972 [pool-1-thread-4] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample3 - 3 is continue
10:49:23.971 [pool-1-thread-2] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample3 - 1 is continue
10:49:23.972 [pool-1-thread-3] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample3 - 2 is continue
10:49:24.972 [pool-1-thread-6] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample3 - 5 is ready
10:49:25.972 [pool-1-thread-3] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample3 - 6 is ready
10:49:26.972 [pool-1-thread-2] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample3 - 7 is ready
10:49:27.973 [pool-1-thread-5] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample3 - 8 is ready
10:49:28.973 [pool-1-thread-4] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample3 - 9 is ready
10:49:28.973 [pool-1-thread-4] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample3 - 當線程等待數達到設定值,優先執行此線程
10:49:28.973 [pool-1-thread-4] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample3 - 9 is continue
10:49:28.973 [pool-1-thread-2] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample3 - 7 is continue
10:49:28.973 [pool-1-thread-6] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample3 - 5 is continue
10:49:28.973 [pool-1-thread-3] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample3 - 6 is continue
10:49:28.973 [pool-1-thread-5] INFO com.mmall.concurrency.example.aqs.CyclicBarrierExample3 - 8 is continue
Process finished with exit code 0
結果與預期的一致。
Java併發編程學習系列
如有幫助,煩請點贊收藏一下啦 (◕ᴗ◕✿)