CyclicBarrier簡介
CyclicBarrier 的字面意思是可循環(huán)(Cyclic)使用的屏障(Barrier)。它要做的事情是,讓一組線程到達一個屏障(也可以叫同步點)時被阻塞,直到最后一個線程到達屏障時,屏障才會開門,所有被屏障攔截的線程才會繼續(xù)干活。線程進入屏障通過CyclicBarrier的await()方法。
CyclicBarrier默認的構(gòu)造方法是CyclicBarrier(int parties),其參數(shù)表示屏障攔截的線程數(shù)量,每個線程調(diào)用await方法告訴CyclicBarrier我已經(jīng)到達了屏障,然后當(dāng)前線程被阻塞。
CyclicBarrier還提供一個更高級的構(gòu)造函數(shù)CyclicBarrier(int parties, Runnable barrierAction),用于在線程到達屏障時,優(yōu)先執(zhí)行barrierAction這個Runnable對象,方便處理更復(fù)雜的業(yè)務(wù)場景。
await方法
調(diào)用await方法的線程告訴CyclicBarrier自己已經(jīng)到達同步點,然后當(dāng)前線程被阻塞。直到parties個參與線程調(diào)用了await方法,解除鎖定狀態(tài),CyclicBarrier同樣提供帶超時時間的await和不帶超時時間的await方法:
public int await() throws InterruptedException, BrokenBarrierException {
try {
// 不超時等待
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
public int await(long timeout, TimeUnit unit)
throws InterruptedException,
BrokenBarrierException,
TimeoutException {
return dowait(true, unit.toNanos(timeout));
}
實例
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
public class CyclicBarrierTest {
private static class NormalTask implements Runnable {
CyclicBarrier barrier;
NormalTask(CyclicBarrier barrier) {
this.barrier = barrier;
}
@Override
public void run() {
try {
Thread.sleep(2000);
System.out.println(Thread.currentThread().getName()+"時間"+System.currentTimeMillis());
barrier.await();
} catch (InterruptedException | BrokenBarrierException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis() + " first step finished");
}
}
private static class FinalTask implements Runnable {
public FinalTask() {
}
@Override
public void run() {
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis() + " second step finished");
}
}
public static void main(String[] args) throws InterruptedException {
//第一個2表示當(dāng)有2個線程調(diào)用await方法時解鎖,第二個參數(shù)是解鎖后優(yōu)先執(zhí)行線程
CyclicBarrier barrier = new CyclicBarrier(2,new FinalTask());
new Thread(new NormalTask(barrier),"線程1").start();
new Thread(new NormalTask(barrier),"線程2").start();
}
}
執(zhí)行結(jié)果:
線程1時間1587799990409
線程2時間1587799990409
1587799994409 second step finished
1587799994409 first step finished
1587799994409 first step finished
發(fā)現(xiàn)線程1和線程2雖然都在4秒前到達await,鎖已經(jīng)解開,但是并沒有直接結(jié)束,而是等待4秒,讓優(yōu)先線程跑完,才執(zhí)行結(jié)束線程1和2.
如果我不設(shè)置優(yōu)先線程,則是這樣的
FinalTask finalTask = new FinalTask();
CyclicBarrier barrier = new CyclicBarrier(2);
new Thread(new NormalTask(barrier),"線程1").start();
new Thread(new NormalTask(barrier),"線程2").start();
new Thread(finalTask,"線程3").start();
執(zhí)行結(jié)果
線程1時間1587800302651
線程2時間1587800302651
1587800302652 first step finished
1587800302652 first step finished
1587800304651 second step finished
線程1,2都到達await后即解鎖,由于沒有優(yōu)先線程的存在,則1,2直接完成。
CyclicBarrier和CountDownLatch的區(qū)別
1.CyclicBarrier和CountDownLatch的區(qū)別CountDownLatch的計數(shù)器只能使用一次,而CyclicBarrier的計數(shù)器可以使用reset()方法重置,可以使用多次,所以CyclicBarrier能夠處理更為復(fù)雜的場景;
2.CyclicBarrier還提供了一些其他有用的方法,比如getNumberWaiting()方法可以獲得CyclicBarrier阻塞的線程數(shù)量,isBroken()方法用來了解阻塞的線程是否被中斷;
3.CountDownLatch允許一個或多個線程等待一組事件的產(chǎn)生,而CyclicBarrier用于等待其他線程運行到柵欄位置。