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其實和鎖有點相似,它通常用於控制對某組資源的訪問權限。