CyclicBarrier、CountDownLatch、Semaphore 的用法
阿新 • • 發佈:2020-08-14
一、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()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 其實和鎖有點類似,它一般用於控制對某組資源的訪問許可權。