CountDownLatch(閉鎖)、Semaphore(信號量)、CyclicBarrier

1、CountDowmLatch(閉鎖)(倒計數鎖存器)java

  CountDownLatch類位於java.util.concurrent包下,在完成某些運算時,只有其餘全部線程的運算所有完成,當前運算才繼續執行。ui

  利用它能夠實現相似計數器的功能。好比有一個任務A,它要等待其餘4個任務執行完畢以後才能執行,此時就能夠利用CountDownLatch來實現這種功能。this

 1 final CountDownLatch latch = new CountDownLatch(2);  2 new Thread(){  3     public void run() {  4         System.out.println("子線程"+Thread.currentThread().getName()+"正在執行");  5         Thread.sleep(3000);  6         System.out.println("子線程"+Thread.currentThread().getName()+"執行完畢");  7  latch.countDown();  8  };  9 }.start(); 10 new Thread(){ 11     public void run() { 12         System.out.println("子線程"+Thread.currentThread().getName()+"正在執行"); 13         Thread.sleep(3000); 14         System.out.println("子線程"+Thread.currentThread().getName()+"執行完畢"); 15  latch.countDown(); 16  }; 17 }.start(); 18 System.out.println("等待 2 個子線程執行完畢..."); 19 latch.await(); 20 System.out.println("2 個子線程已經執行完畢"); 21 System.out.println("繼續執行主線程"); 22 }

2、Semaphore(信號量-控制同時訪問的線程個數)spa

  信號量能夠控制同時訪問的線程個數,經過acquire()獲取一個許可,若是沒有就等待,而經過release()釋放一個許可。線程

Semaphore類中比較重要的幾個方法:code

  1)public void acquire():用來獲取一個許可,若無許可可以得到,則會一直等待,知道得到許可。blog

  2)public void acquire(int permits):獲取permits個許可。資源

  3)public void release(){}:釋放許可,注意,在釋放許可以前,必須先得到許可。get

  4)public void release(int permits){}:釋放permits個許可。it

上面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臺機器,一臺機器同時只能被一個工人使用,只有使用完了,其餘工人才能繼續使用。那麼咱們就能夠經過Semaphore來實現:

 1 int N = 8; //工人數
 2 Semaphore semaphore = new Semaphore(5); //機器數目
 3 for(int i=0;i<N;i++){  4     new Worker(i,semaphore).start();  5 }  6 static class Worker extends Thread{  7     private int num;  8     private Semaphore semaphore;  9     public Worker(int num,Semaphore semaphore){ 10         this.num = num; 11         this.semaphore = semaphore; 12  } 13     public void run() { 14         try { 15  semaphore.acquire(); 16             System.out.println("工人"+this.num+"佔用一個機器在生產..."); 17             Thread.sleep(2000); 18             System.out.println("工人"+this.num+"釋放出機器"); 19  semaphore.release(); 20         } catch (InterruptedException e) { 21  e.printStackTrace(); 22  } 23  } 24 }

3、CyclicBarrier(迴環柵欄-等待至barrier狀態再所有同時執行)

  迴環柵欄,經過它能夠實現讓一組線程等待至某個狀態以後再所有同時執行,叫作迴環,是由於當全部等待線程都被釋放之後,CyclicBarrier能夠被重用。咱們暫且把這種狀態叫作barrier,當調用await()方法以後,線程就處於barrier了。

  CyclicBarrier中最重要的方法就是await方法,它有兩個重載版本:

    1)public int await():用來掛起當前線程,直至全部線程都到達barrier狀態再同時執行後續任務。

    2)public int await(long timeout,TimeUnit unit):讓這些線程等待至必定的時間,若是還有線程沒有到達barrier狀態就直接讓到達barrier的線程執行後續任務。

  具體使用以下:

 1  public static void main(String[] args) {  2      int N = 4;  3      CyclicBarrier barrier = new CyclicBarrier(N);  4      for(int i=0;i<N;i++)  5          new Writer(barrier).start();  6  }  7  static class Writer extends Thread{  8      private CyclicBarrier cyclicBarrier;  9      public Writer(CyclicBarrier cyclicBarrier) { 10          this.cyclicBarrier = cyclicBarrier; 11  } 12  public void run() { 13      try { 14          Thread.sleep(5000); //以睡眠來模擬線程須要預約寫入數據操做
15 System.out.println("線程"+Thread.currentThread().getName()+"寫入數據完畢,等待其餘線程寫入完畢"); 16  cyclicBarrier.await(); 17      } catch (InterruptedException e) { 18  e.printStackTrace(); 19      }catch(BrokenBarrierException e){ 20  e.printStackTrace(); 21  } 22      System.out.println("全部線程寫入完畢,繼續處理其餘任務,好比數據操做"); 23  } 24  }

 

三者之間的聯繫與區別:

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

  Semaphore其實和鎖有點相似,它通常用於控制對某組資源的訪問權限。

相關文章
相關標籤/搜索