Java併發程式設計之——CyclicBarrier的使用
阿新 • • 發佈:2019-01-06
首先看一下官方關於CyclicBarrier的簡介:
/** * A synchronization aid that allows a set of threads to all wait for * each other to reach a common barrier point. CyclicBarriers are * useful in programs involving a fixed sized party of threads that * must occasionally wait for each other. The barrier is called * <em>cyclic</em> because it can be re-used after the waiting threads * are released.
這段話的意思是:CyclicBarrier允許一組執行緒相互等待達到一個公共的障礙點。CyclicBarrier對於一組執行緒必須相互等待的場景很有用。比如有一組執行緒,都要往資料庫裡面寫入操作,只有當所有的執行緒都往資料庫裡面寫入資料之後,這些執行緒才能繼續往下執行,這時候就可以使用CyclicBarrier了。當所有的等待執行緒釋放之後,CyclicBarrier是可重用的。
CyclicBarrier有兩個建構函式:
public CyclicBarrier(int parties, Runnable barrierAction)
引數parties指讓多少個執行緒或者任務等待至barrier狀態;引數barrierAction為當這些執行緒都達到barrier狀態時會執行的內容。public CyclicBarrier(int parties)
對於CyclicBarrier來說,最重要的是await()方法:
public int await() throws InterruptedException, BrokenBarrierException
public int await(long timeout, TimeUnit unit)
第一個版本比較常用,用來掛起當前執行緒,直至所有執行緒都到達barrier狀態再同時執行後續任務;
第二個版本是讓這些執行緒等待至一定的時間,如果還有執行緒沒有到達barrier狀態就直接讓到達barrier的執行緒執行後續任務。
下面看程式碼實現:
package com.easyliu.java.demo.cyclicbarrier;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CyclicBarrierTest {
private static final int THREAD_NUMBER = 3;
private static CyclicBarrier sCyclicBarrier = new CyclicBarrier(
THREAD_NUMBER, new Runnable() {
@Override
public void run() {
System.out.println("大家都到達了宿舍樓下,一起出發吧。。。");
}
});
public static void main(String[] args) {
ExecutorService executorService = Executors
.newFixedThreadPool(THREAD_NUMBER);
for (int i = 0; i < THREAD_NUMBER; i++) {
executorService.execute(new WalkFromDomitoryToCanteenRunnable(
sCyclicBarrier, "同學" + i));
}
try {
Thread.sleep(10000);//主執行緒睡眠
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("CyclicBarrier重用");
for (int i = THREAD_NUMBER; i < THREAD_NUMBER * 2; i++) {
executorService.execute(new WalkFromDomitoryToCanteenRunnable(
sCyclicBarrier, "同學" + i));
}
}
/**
* 從宿舍到食堂執行緒
*
* @author LiuYi
*
*/
public static class WalkFromDomitoryToCanteenRunnable implements Runnable {
private CyclicBarrier mCyclicBarrier;
private String mName;
public WalkFromDomitoryToCanteenRunnable(CyclicBarrier cyclicBarrier,
String name) {
this.mCyclicBarrier = cyclicBarrier;
this.mName = name;
}
@Override
public void run() {
System.out.println(mName + "開始從宿舍出發。。。");
try {
Thread.sleep(1000);
mCyclicBarrier.await();// 等待別同學
// 前往食堂
System.out.println(mName + "開始從宿舍樓下出發。。。");
Thread.sleep(1000);
System.out.println(mName + "達到食堂。。。");
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
}
輸出結果如下:
同學1開始從宿舍出發。。。
同學0開始從宿舍出發。。。
同學2開始從宿舍出發。。。
大家都到達了宿舍樓下,一起出發吧。。。
同學1開始從宿舍樓下出發。。。
同學2開始從宿舍樓下出發。。。
同學0開始從宿舍樓下出發。。。
同學0達到食堂。。。
同學1達到食堂。。。
同學2達到食堂。。。
CyclicBarrier重用
同學3開始從宿舍出發。。。
同學5開始從宿舍出發。。。
同學4開始從宿舍出發。。。
大家都到達了宿舍樓下,一起出發吧。。。
同學5開始從宿舍樓下出發。。。
同學4開始從宿舍樓下出發。。。
同學3開始從宿舍樓下出發。。。
同學4達到食堂。。。
同學3達到食堂。。。
同學5達到食堂。。。
從輸出結果可以看出實現了我們想要的效果,並且實現了CyclicBarrier的重用,因為初始化CyclicBarrier的時候只設置了讓三個執行緒等待至barrier狀態,也就是當有三個同學到達了宿舍樓下之後,就一起走。剩下的三個同學一起走。
CountDownLatch和CyclicBarrier都能夠實現執行緒之間的等待,只不過它們側重點不同:
CountDownLatch一般用於某個執行緒A等待若干個其他執行緒執行完任務之後,它才執行;
而CyclicBarrier一般用於一組執行緒互相等待至某個狀態,然後這一組執行緒再同時執行;
另外,CountDownLatch是不能夠重用的,而CyclicBarrier是可以重用的。