Java並發之CountDownLatch、CyclicBarrier和Semaphore

來源:互聯網
上載者:User

標籤:

CountDownLatch 是能使一組線程等另一組線程都跑完了再繼續跑;CyclicBarrier 能夠使一組線程在一個時間點上達到同步,可以是一起開始執行全部任務或者一部分任務。

 

這次說一下 JUC 中的同步器三個主要的成員:CountDownLatch、CyclicBarrier 和 Semaphore(不知道有沒有初學者覺得這三個的名字不太好記)。這三個是 JUC 中較為常用的同步器,通過它們可以方便地實現很多線程之間協作的功能。(下面的代碼出自 JDK 文檔)

CountDownLatch

直譯過來就是倒計數(CountDown)門閂(Latch)。倒計數不用說,門閂的意思顧名思義就是阻止前進。在這裡就是指 CountDownLatch.await() 方法在倒計數為0之前會阻塞當前線程。

作用

CountDownLatch 的作用和 Thread.join() 方法類似,可用於一組線程和另外一組線程的協作。例如,主線程在做一項工作之前需要一系列的準備工作,只有這些準備工作都完成,主線程才能繼續它的工作。這些準備工作彼此獨立,所以可以並發執行以提高速度。在這個情境下就可以使用 CountDownLatch 協調線程之間的調度了。在直接建立線程的年代(Java 5.0 之前),我們可以使用 Thread.join()。在 JUC 出現後,因為線程池中的線程不能直接被引用,所以就必須使用 CountDownLatch 了。

樣本

下面的這個例子可以理解為 F1 賽車的維修過程,只有 startSignal (可以表示停車,可能名字不太貼合)命令下達之後,維修工才開始幹活,只有等所有工人完成工作之後,賽車才能繼續。

  1. class Driver { // ...  
  2.     void main() throws InterruptedException {  
  3.         CountDownLatch startSignal = new CountDownLatch(1);  
  4.         CountDownLatch doneSignal = new CountDownLatch(N);  
  5.  
  6.         for (int i = 0; i < N; ++i) // create and start threads  
  7.             new Thread(new Worker(startSignal, doneSignal)).start();  
  8.  
  9.         doSomethingElse();            // don‘t let run yet  
  10.         startSignal.countDown();      // let all threads proceed  
  11.         doSomethingElse();  
  12.         doneSignal.await();           // wait for all to finish  
  13.     }  
  14. }  
  15.  
  16. class Worker implements Runnable {  
  17.     private final CountDownLatch startSignal;  
  18.     private final CountDownLatch doneSignal;  
  19.     Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {  
  20.         this.startSignal = startSignal;  
  21.         this.doneSignal = doneSignal;  
  22.     }  
  23.     public void run() {  
  24.         try {  
  25.             startSignal.await();  
  26.             doWork();  
  27.             doneSignal.countDown();  
  28.         } catch (InterruptedException ex) {} // return;  
  29.     }  
  30.  
  31.     void doWork() { ... }  

當 startSignal.await() 會阻塞線程,當 startSignal.countDown() 被調用之後,所有 Worker 線程開始執行 doWork() 方法,所以 Worker。doWork() 是幾乎同時開始執行的。當 Worker.doWork() 執行完畢後,調用 doneSignal.countDown(),在所有 Worker 線程執行完畢之後,主線程繼續執行。

CyclicBarrier

CyclicBarrier 翻譯過來叫迴圈柵欄、迴圈障礙什麼的(還是有點彆扭的。所以還是別翻譯了,只可意會不可言傳啊)。它主要的方法就是一個:await()。await() 方法沒被調用一次,計數便會減少1,並阻塞住當前線程。當計數減至0時,阻塞解除,所有在此 CyclicBarrier 上面阻塞的線程開始運行。在這之後,如果再次調用 await() 方法,計數就又會變成 N-1,新一輪重新開始,這便是 Cyclic 的含義所在。

CyclicBarrier 的使用並不難,但需要主要它所相關的異常。除了常見的異常,CyclicBarrier.await() 方法會拋出一個專屬的 BrokenBarrierException。這個異常發生在當某個線程在等待本 CyclicBarrier 時被中斷或逾時或被重設時,其它同樣在這個 CyclicBarrier 上等待的線程便會受到 BrokenBarrierException。意思就是說,同志們,別等了,有個小夥伴已經掛了,咱們如果繼續等有可能會一直等下去,所有各回各家吧。

CyclicBarrier.await() 方法帶有傳回值,用來表示當前線程是第幾個到達這個 Barrier 的線程。

和 CountDownLatch 一樣,CyclicBarrier 同樣可以可以在建構函式中設定總計數值。與 CountDownLatch 不同的是,CyclicBarrier 的建構函式還可以接受一個 Runnable,會在 CyclicBarrier 被釋放時執行。

 

import java.util.Random;import java.util.concurrent.CyclicBarrier;/** *//** * CyclicBarrier類似於CountDownLatch也是個計數器, * 不同的是CyclicBarrier數的是調用了CyclicBarrier.await()進入等待的線程數, * 當線程數達到了CyclicBarrier初始時規定的數目時,所有進入等待狀態的線程被喚醒並繼續。 * CyclicBarrier就象它名字的意思一樣,可看成是個障礙, * 所有的線程必須到齊後才能一起通過這個障礙。 * CyclicBarrier初始時還可帶一個Runnable的參數, * 此Runnable任務在CyclicBarrier的數目達到後,所有其它線程被喚醒前被執行。 */public class CyclicBarrierTest {    public static class ComponentThread implements Runnable {        CyclicBarrier barrier;// 計數器        int ID;    // 組件標識        int[] array;    // 資料數組        // 構造方法        public ComponentThread(CyclicBarrier barrier, int[] array, int ID) {            this.barrier = barrier;            this.ID = ID;            this.array = array;        }        public void run() {            try {                array[ID] = new Random().nextInt(100);                System.out.println("Component " + ID + " generates: " + array[ID]);                // 在這裡等待Barrier處                System.out.println("Component " + ID + " sleep");                barrier.await();                System.out.println("Component " + ID + " awaked");                // 計算資料數組中的當前值和後續值                int result = array[ID] + array[ID + 1];                System.out.println("Component " + ID + " result: " + result);            } catch (Exception ex) {            }        }    }    /** *//**     * 測試CyclicBarrier的用法     */    public static void testCyclicBarrier() {        final int[] array = new int[3];        CyclicBarrier barrier = new CyclicBarrier(2, new Runnable() {            // 在所有線程都到達Barrier時執行            public void run() {                System.out.println("testCyclicBarrier run");                array[2] = array[0] + array[1];            }        });        // 啟動線程        new Thread(new ComponentThread(barrier, array, 0)).start();        new Thread(new ComponentThread(barrier, array, 1)).start();    }    public static void main(String[] args) {        CyclicBarrierTest.testCyclicBarrier();    }}

 

三、Semaphore 訊號量

Semaphore翻譯成字面意思為 訊號量,Semaphore可以控同時訪問的線程個數,通過 acquire() 擷取一個許可,如果沒有就等待,而 release() 釋放一個許可。

下面通過一個例子來看一下Semaphore的具體使用:

  假若一個工廠有5台機器,但是有8個工人,一台機器同時只能被一個工人使用,只有使用完了,其他工人才能繼續使用。那麼我們就可以通過Semaphore來實現:

public class Test {    public static void main(String[] args) {        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();            }        }    }}

 

Java並發之CountDownLatch、CyclicBarrier和Semaphore

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.