1. 程式人生 > 實用技巧 >CyclicBarrier、CountDownLatch、Semaphore 的用法

CyclicBarrier、CountDownLatch、Semaphore 的用法

一、CountDownLatch(執行緒計數器 )

  CountDownLatch 類位於 java.util.concurrent 包下,利用它可以實現類似計數器的功能。比如有一個任務 A,它要等待其他 4 個任務執行完畢之後才能執行,此時就可以利用 CountDownLatch來實現這種功能了。
final CountDownLatch latch = new CountDownLatch(2);
new Thread(){public void run() {
    System.out.println("子執行緒"+Thread.currentThread().getName()+"正在執行");
     Thread.sleep(3000);
     System.out.println("子執行緒"+Thread.currentThread().getName()+"執行完畢");
     latch.countDown();
};}.start();
new Thread(){ public void run() {
    System.out.println("子執行緒"+Thread.currentThread().getName()+"正在執行");
     Thread.sleep(3000);
     System.out.println("子執行緒"+Thread.currentThread().getName()+"執行完畢");
     latch.countDown();
};}.start();
System.out.println("等待 2 個子執行緒執行完畢...");
latch.await();
System.out.println("2 個子執行緒已經執行完畢");
System.out.println("繼續執行主執行緒");

二、CyclicBarrier(迴環柵欄-等待至 barrier 狀態再全部同時執行)

  字面意思迴環柵欄,通過它可以實現讓一組執行緒等待至某個狀態之後再全部同時執行。叫做迴環是因為當所有等待執行緒都被釋放以後,CyclicBarrier 可以被重用。我們暫且把這個狀態就叫做barrier,當呼叫 await()方法之後,執行緒就處於 barrier 了。 CyclicBarrier 中最重要的方法就是 await 方法,它有 2 個過載版本: 1. public int await():用來掛起當前執行緒,直至所有執行緒都到達 barrier 狀態再同時執行後續任務; 2. public int await(long timeout, TimeUnit unit):讓這些執行緒等待至一定的時間,如果還有執行緒沒有到達 barrier 狀態就直接讓到達 barrier 的執行緒執行後續任務。 具體使用如下,另外 CyclicBarrier 是可以重用的。
public static void main(String[] args) {
     int N = 4;
     CyclicBarrier barrier = new CyclicBarrier(N);
     for(int i=0;i<N;i++)
         new Writer(barrier).start();
     }
}
     static class Writer extends Thread{
         private CyclicBarrier cyclicBarrier;
         public Writer(CyclicBarrier cyclicBarrier) {
             this.cyclicBarrier = cyclicBarrier;
         }
         @Override
         public void run() {
             try {
                 Thread.sleep(5000); //以睡眠來模擬執行緒需要預定寫入資料操作
                System.out.println("執行緒"+Thread.currentThread().getName()+"寫入資料完
畢,等待其他執行緒寫入完畢");
                 cyclicBarrier.await();
             } catch (InterruptedException e) {
                     e.printStackTrace();
             }catch(BrokenBarrierException e){
                 e.printStackTrace();
             }
             System.out.println("所有執行緒寫入完畢,繼續處理其他任務,比如資料操作");
         }
     }

三、Semaphore(訊號量-控制同時訪問的執行緒個數)

  Semaphore 翻譯成字面意思為 訊號量,Semaphore 可以控制同時訪問的執行緒個數,通過acquire() 獲取一個許可,如果沒有就等待,而 release() 釋放一個許可。 Semaphore 類中比較重要的幾個方法: 1. public void acquire(): 用來獲取一個許可,若無許可能夠獲得,則會一直等待,直到獲得許可。 2. public void acquire(int permits):獲取 permits 個許可 3. public void release() { } :釋放許可。注意,在釋放許可之前,必須先獲得許可。 4. public void release(int permits) { }:釋放 permits 個許可 上面 4 個方法都會被阻塞,如果想立即得到執行結果,可以使用下面幾個方法 1. public boolean tryAcquire()
:嘗試獲取一個許可,若獲取成功,則立即返回 true,若獲取失敗,則立即返回 false 2. public boolean tryAcquire(long timeout, TimeUnit unit):嘗試獲取一個許可,若在指定的時間內獲取成功,則立即返回 true,否則則立即返回 false 3. public boolean tryAcquire(int permits):嘗試獲取 permits 個許可,若獲取成功,則立即返回 true,若獲取失敗,則立即返回 false 4. public boolean tryAcquire(int permits, long timeout, TimeUnit unit): 嘗試獲取 permits個許可,若在指定的時間內獲取成功,則立即返回 true,否則則立即返回 false 5. 還可以通過 availablePermits()方法得到可用的許可數目。 例子:若一個工廠有 5 臺機器,但是有 8 個工人,一臺機器同時只能被一個工人使用,只有使用完了,其他工人才能繼續使用。那麼我們就可以通過 Semaphore 來實現:
int N = 8; //工人數
Semaphore semaphore = new Semaphore(5); //機器數目
for(int i=0;i<N;i++){
   new Worker(i,semaphore).start();
}
static class Worker extends Thread{
    private int num;
    private Semaphore semaphore;
    public Worker(int num,Semaphore semaphore){
        this.num = num;
        this.semaphore = semaphore;
    }
    @Override
    public void run() {
        try {
            semaphore.acquire();
            System.out.println("工人"+this.num+"佔用一個機器在生產...");
            Thread.sleep(2000);
            System.out.println("工人"+this.num+"釋放出機器");
            semaphore.release();
        } catch (InterruptedException e) {
            e.printStackTrace();
    }
}

  

1. CountDownLatch 和 CyclicBarrier 都能夠實現執行緒之間的等待,只不過它們側重點不同;CountDownLatch 一般用於某個執行緒 A 等待若干個其他執行緒執行完任務之後,它才 執行;而 CyclicBarrier 一般用於一組執行緒互相等待至某個狀態,然後這一組執行緒再同時執行;另外,CountDownLatch 是不能夠重用的,而 CyclicBarrier 是可以重用的。

2.Semaphore 其實和鎖有點類似,它一般用於控制對某組資源的訪問許可權。