CountDownLatch.CyclicBarrier和 Semaphore
一 CountDownLatch
1.使用場景(與join方法類似)
1:某一執行緒在開始執行前等待n個執行緒執行完畢。
2:實現多個執行緒開始執行任務的最大並行性。強調的是多個執行緒在某一時刻同時開始執行。類似於賽跑,將多個執行緒放到起點,等待發令槍響,然後同時開跑。
2.用法
建立
CountDownLatch countDownLatch = new CountDownLatch(n);
建構函式傳入一個int型別的n作為計數器,你想等待n個執行緒完成,就傳入n;
呼叫await()方法時,當前執行緒阻塞,直到n等於0;
呼叫countDown()方法時,n就會減一,當n等於0時,阻塞的執行緒開始執行。
還有一個 await(long timeout, TimeUnit unit) 方法,指定等待的時間,當超過特定時間後,將不再阻塞當前執行緒。
3.內部實現
內部通過自定義一個同步器來繼承同步佇列,
private static final class Sync extends AbstractQueuedSynchronizer{
}
建立
public CountDownLatch(int count) { if (count < 0) throw new IllegalArgumentException("count < 0"); this.sync = new Sync(count); }
其他方法都是通過呼叫同步器方法來完成的。
二. CyclicBarrier
1.使用場景
可以實現讓一組執行緒等待至某個狀態之後再全部同時執行。
2.用法
建立
CyclicBarrier c = new CyclicBarrier(n); n表示屏障攔截的數量
CyclicBarrier(int parties, Runnable barrierAction) 表示當所有執行緒到達屏障,準備開始執行時,優先執行barrierAction所對應的任務。
await()方法表示,告訴CyclicBarrier我已經到達了屏障,然後當前執行緒被阻塞,然後內部計數器加1。 當內部計數器的數值等於n時,所有被阻塞的執行緒全部開始執行。
await(long timeout, TimeUnit unit)
讓這些執行緒等待至一定的時間,如果還有執行緒沒有到達barrier狀態就直接讓到達barrier的執行緒執行後續任務。
三.Semaphore
1.使用場景
用來控制對特定資源的訪問,比如資料庫連線池。
2.用法
Semaphore(int permits) permits表示最大的資源訪問量,可以理解為許可證總量。
Semaphore(int permits, boolean fair)。可以通過設定fair欄位來完成公平鎖與非公平鎖的設定。
acquire()方法表示,當前執行緒拿走了一個許可證,總的許可證數量減1,可用資源訪問量減1.
release()方法表示,當前執行緒釋放了一個許可證,總的許可證數量加1. 在釋放許可之前,必須先獲獲得許可。
關於公平鎖與非公平鎖。當沒有許可證可以獲取時,呼叫acquire()方法的執行緒堵塞,並加入FIFO(雙向)佇列。當有執行緒釋放許可證時,如果是公平鎖,則時間上先獲取許可證(即先呼叫acquire()方法)的執行緒會先獲取到許可證。
而對於非公平鎖,所有在佇列中阻塞的執行緒,會用搶佔式的方法來獲取許可證,可以減少執行緒切換,提高併發量。
3.內部實現
內部也是自定義同步器來繼承同步佇列(AQS)
abstract static class Sync extends AbstractQueuedSynchronizer { }
總結
1)CountDownLatch和CyclicBarrier都能夠實現執行緒之間的等待,只不過它們側重點不同:
CountDownLatch一般用於某個執行緒A等待若干個其他執行緒執行完任務之後,它才執行;
而CyclicBarrier一般用於一組執行緒互相等待至某個狀態,然後這一組執行緒再同時執行;
另外,CountDownLatch是不能夠重用的,內部是通過計數器減的方式,當到達0時釋放所有等待執行緒,無法重置。
而CyclicBarrier是可以重用的,內部通過計數器加的方式,當到達指定數量時,釋放所有等待執行緒,可以通過呼叫reset()重置。
2)Semaphore其實和鎖有點類似,它一般用於控制對某組資源的訪問許可權。