1. CountDownLatch 類
CountDownLatch 類是用於線程同步的工具,作用:讓一個或多個源線程(調用await方法的線程) 必須 等待一個或多個目標線程(調用countDown方法的線程)都執行完成了才能繼續執行自己的代碼。
注意:
1. 不會妨礙目標線程的執行,但是會阻塞源線程,因爲await方法會檢測count是爲0,如果不是0,就會阻塞,不會繼續執行後面的代碼。
2. 它是一次性的,不能重複用,因爲count變爲0之後,就不會再改變了,只有一個countDown方法去減,沒有方法去讓count加,所以如果你重複使用的話,不起作用,count永遠爲0。
3. 當然,你可以在一個線程的run方法裏調用多次countDown 方法,多減幾個1。
比如一個測評系統,需要測評一個人的優秀值good,good是通過一個計算公式來計算出的,這個公式爲good = 身高 + 體重 + 智力 + 情商 + 顏值,那麼我們可以創建5個線程A,B,C,D,E,分別去測試出:身高、體重、智力、情商、顏值,要想計算出good,必須等待5個線程都執行完畢,身高、體重、智力、情商、顏值都得到了,才能進一步計算good。 此時CountDownLatch類就有用了。
public class CountDownLatch {
// 構造方法,初始化計數值
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
//判斷count是否爲0,爲0才能繼續執行下去,否則就一直阻塞
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
//判斷count是否爲0,爲0才能繼續執行下去,否則就一直阻塞,如果阻塞時間超過了unit,就繼續執行
public boolean await(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
//讓count減1
public void countDown() {
sync.releaseShared(1);
}
//獲取count的值
public long getCount() {
return sync.getCount();
}
}
舉個例子:
其實這個例子裏面不應該將CountDownLatch對象定爲靜態的(定義爲普通的就行),因爲不能重複使用,定義爲靜態的幹嘛。
public class Main {
public static CountDownLatch countDownLatch = new CountDownLatch(2);
public static void main(String[] args) throws InterruptedException {
MyThread myThread = new MyThread();
myThread.start();
MyThread myThread1 = new MyThread();
myThread1.start();
countDownLatch.await();
System.out.println("徹底結束啦");
}
}
public class MyThread extends Thread {
@Override
public void run() {
super.run();
System.out.println("當前線程是:" + Thread.currentThread().getName());
Main.countDownLatch.countDown();
System.out.println("結束");
}
}
2. CyclicBarrier類
CyclicBarrier 類也是線程同步工具類,CountDownLatch類能做到的,它都能做到,而且功能更多,作用:僅僅讓多個線程同時開始執行。 形象地比喻爲柵欄,所有達到柵欄的線程都得停下,只能線程數量達到了規定的數量後,纔打開柵欄,讓所有線程同時繼續運行。
注意:
1. 它不會阻塞源線程,但是它阻塞目標線程。
2. 能夠重複使用,就好像count減爲0之後,我們能夠調用reset方法將count再次重置爲初始值。
3. 不用特意調用reset方法去達到循環使用,比如parties是3,直接啓動3個線程後,接着直接啓動別的線程就行。
public class CyclicBarrier {
//用於記錄同一批線程屬於一代
private static class Generation {
boolean broken = false;
}
//入口鎖,就是要達到柵欄,也得一個一個來吧,不能兩個線程同時進行吧,因此要一個鎖
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();
//count類似於CountDownLatch中的count
private int count;
//進入下一代了,上一批線程已經處理完了,可以接受下一批了
private void nextGeneration() {
trip.signalAll();
count = parties;
generation = new Generation();
}
//終止柵欄
private void breakBarrier() {
generation.broken = true;
count = parties;
trip.signalAll();
}
//await就是通過dowait實現的
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();
}
int index = --count;
if (index == 0) { // tripped
boolean ranAction = false;
try {
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
nextGeneration();
return 0;
} finally {
if (!ranAction)
breakBarrier();
}
}
// loop until tripped, broken, interrupted, or timed out
for (;;) {
try {
if (!timed)
trip.await();
else if (nanos > 0L)
nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
if (g == generation && ! g.broken) {
breakBarrier();
throw ie;
} else {
// We're about to finish waiting even if we had not
// been interrupted, so this interrupt is deemed to
// "belong" to subsequent execution.
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();
}
}
//構造方法,當柵欄被開啓時,barrierAction由最後一個到達柵欄的線程執行
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties;
this.count = parties;
this.barrierCommand = barrierAction;
}
// 構造方法
public CyclicBarrier(int parties) {
this(parties, null);
}
// 獲取打開柵欄所需的線程數量,就是我們初始化時候指定的那個int參數
public int getParties() {
return parties;
}
// 調用這個方法的線程已經就緒等待了
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L);
} catch (TimeoutException toe) {
throw new Error(toe); // cannot happen
}
}
// 這個方法是目標線程調用的,表示調用此方法的線程已經就緒等待着,
// 如果等待時間超過unit,就不等了,直接執行自己的
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(); // break the current generation
nextGeneration(); // start a new generation
} finally {
lock.unlock();
}
}
// 獲取當前正等待着的(或者說準備就緒了)線程的數量
public int getNumberWaiting() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return parties - count;
} finally {
lock.unlock();
}
}
}