1.CyclicBarrier工具類的特點
CyclicBarrier採用一種屏障的方式來控制線程,讓所有線程停在某一點,已到的等最後到才完事。先到的線程將處於阻塞的狀態。
2.初識CyclicBarrier
http://blog.csdn.net/ya_1249463314/article/details/52822580
3.CyclicBarrier所屬包
package java.util.concurrent;
4.CyclicBarrier的繼承與實現關係
public class CyclicBarrier
5.屬性
說明:下面所說的線程組是指啓動此 barrier 的參與者(所有線程)被叫做線程組。
屬性:
/** 定義一個排他鎖 */
private final ReentrantLock lock = new ReentrantLock();
/** 創建一個等待隊列 */
private final Condition trip = lock.newCondition();
/** 等待線程的數量 */
private final int parties;
/* 當柵欄被釋放後執行的線程 */
private final Runnable barrierCommand;
/** 當前的一代線程組 */
private Generation generation = new Generation();
/**
* 在當前一代線程組中等待線程的數量從parties減到0。
* count值是在創建新的一代線程時被重置。
*/
private int count;
內部類:
/**
* 一個柵欄代表了一代線程組,柵欄被重置或者跳閘時,一代線程組發生改變。
* 如果一代線程組被實例化了,那麼這個柵欄被打破的標誌位爲false。
*/
private static class Generation {
boolean broken = false;
}
6.核心實現
breakBarrier:
設置當前的柵欄已經被破壞(說明線程都到達了同一點)並且喚醒所有線程
/**
* 設置當前的柵欄已經被破壞(說明線程都到達了同一點)並且喚醒所有線程
* 在持有鎖的時候,纔可以調用該方法。
*/
private void breakBarrier() {
//設置一代線程組對應的柵欄狀態爲true(意思就是柵欄被破壞了)
generation.broken = true;
//重新設置計數count值
count = parties;
//喚醒所有等待的線程
trip.signalAll();
}
nextGeneration:重新設置下一代線程組
/**
* 重新設置下一代線程組
* 當柵欄跳閘時,就是線程都到達屏障時,就更新同步狀態,然後喚醒所有等待的線程。
* 但是隻能在持有鎖時纔可以調用該方法。
*/
private void nextGeneration() {
//喚醒所有等待的線程
trip.signalAll();
//重新設置計數count值
count = parties;
//重新創建一代線程組
generation = new Generation();
}
doAwait:
主要用於限時等待和非限時等待
/**
* 等待通用方法
*/
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
//獲取當前對象創建的排他鎖
final ReentrantLock lock = this.lock;
//獲取鎖
lock.lock();
try {
//獲取當前這一代線程組
final Generation g = generation;
//如果當前這一代線程組對應的柵欄狀態已經被破壞了
if (g.broken)
throw new BrokenBarrierException();
//如果線程阻塞
if (Thread.interrupted()) {
//設置當前的柵欄已經被破壞
breakBarrier();
//拋出中斷異常
throw new InterruptedException();
}
//獲取一代線程組中等待線程的數量-1
int index = --count;
//如果達到跳閘的條件
if (index == 0) { // tripped
boolean ranAction = false;
try {
//獲取跳閘後執行的線程
final Runnable command = barrierCommand;
//如果該線程不爲空,那麼就執行最後的線程
if (command != null)
command.run();
//將標記位設置爲true
ranAction = true;
//重新設置下一代線程組
nextGeneration();
return 0;
} finally {
if (!ranAction)
breakBarrier();
}
}
// 死循環,除非出現柵欄破壞了、線程中斷、超時情況才結束循環
for (;;) {
try {
/* timed時間標誌位
* 如果timed爲false,那麼線程等待隊列將一直被掛起,線程一直處於等待狀態。
*/
if (!timed)
trip.await();
else if (nanos > 0L)
/**
* 如果時間標誌位timed爲true
* 如果等待時間大於0L,那麼將線程等待隊列在指定時間到達前將等待
*/
nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
//如果當前這一代線程組對應的柵欄狀態未破壞
if (g == generation && ! g.broken) {
//設置當前的柵欄已經被破壞(說明線程都到達了同一點)並且喚醒所有線程
breakBarrier();
//拋出中斷異常
throw ie;
} else {
/* 如果線程沒有結束等待甚至根本沒有中斷,那麼這個中斷操作將會隨後在執行。
*
*/
Thread.currentThread().interrupt();
}
}
if (g.broken)
throw new BrokenBarrierException();
if (g != generation)
return index;
if (timed && nanos <= 0L) {
breakBarrier();
throw new TimeoutException();
}
}
} finally {
//釋放鎖
lock.unlock();
}
}
7.構造方法
/**
* 柵欄構造器
* 輸入參數爲線程組中的等待線程數、最後執行的線程
*/
public CyclicBarrier(int parties, Runnable barrierAction) {
//如果等待線程數不大於0,那麼就拋出非法參數異常
if (parties <= 0) throw new IllegalArgumentException();
//初始化等待線程數
this.parties = parties;
//初始化操作線程數
this.count = parties;
//初始化柵欄破壞後,最後執行的線程
this.barrierCommand = barrierAction;
}
/**
* 柵欄構造器
* 就是沒有最後執行的線程的柵欄
*/
public CyclicBarrier(int parties) {
this(parties, null);
}
8.方法
/**
* 獲取啓動此 barrier 的參與者數目
*/
public int getParties() {
return parties;
}
/**
* 在所有參與者都已經在此屏障上調用 await 方法之前將一直等待,或者超出了指定的等待時間。
*/
public int await(long timeout, TimeUnit unit)
throws InterruptedException,
BrokenBarrierException,
TimeoutException {
return dowait(true, unit.toNanos(timeout));
}
/**
* 查看屏障是否處於破壞狀態
*/
public boolean isBroken() {
//獲取當前的排它鎖
final ReentrantLock lock = this.lock;
//獲取鎖
lock.lock();
try {
//返回當前這一代線程組中的狀態
return generation.broken;
} finally {
//釋放鎖
lock.unlock();
}
}
/**
* 將屏障設置爲初始化的狀態
*/
public void reset() {
//獲取排他鎖
final ReentrantLock lock = this.lock;
//獲取鎖
lock.lock();
try {
//設置當前的柵欄已經被破壞(說明線程都到達了同一點)並且喚醒所有線程
breakBarrier();
//重新設置下一代線程組
nextGeneration();
} finally {
//釋放鎖
lock.unlock();
}
}
/**
* 獲取當前屏障處等待的線程數
*/
public int getNumberWaiting() {
//獲取排他鎖
final ReentrantLock lock = this.lock;
//獲取鎖
lock.lock();
try {
//總等待線程數減去當前剩餘沒到達的線程數
return parties - count;
} finally {
//釋放鎖
lock.unlock();
}
}
--------------------------------------------jdk1.7