淺談CountDownLatch類

淺談CountDownLatch類

CountDownLatch是JDK1.5引入的解決併發問題的新類,在java.util.coucurrent包下,下面先結合JDK中的註釋介紹這個類以及類中常用的方法!

1-類的註釋

提取JDK中類的註釋如下:

A synchronization aid that allows one ormore threads to wait until a set of operations being performed in other threadscompletes.

A CountDownLatch is initialized with a given count.The await methods blockuntil the current count reaches zero due to invocations of the countdown method,after which all waiting threads are released and any subsequent invocations of awaitreturn immediately.  This is a one-shotphenomenon the count cannot be reset.  Ifyou need a version that resets the count, consider using a CyclicBarrier.A CountDownLatchis a versatile synchronization tool and can be used for a number ofpurposes.  A CountDownLatch initialized witha count of one serves as a simple on/off latch, or gate: all threads invoking awaitwait at the gate until it is opened by a thread invoking countDown. A CountDownLatchinitialized to N can be used to make one thread wait until N threads have completedsome action, or some action has been completed N times.

下面嘗試翻譯下上述內容,理解了上述的內容意思就大概可以明白CountDownLatch設計的意圖:

CountDownLatch是一個同步輔助工具,用於使一個或多個線程等待(即阻塞)知道一組在其他線程中的任務結束。

CountDownLatch必須用給定的count(一個int類型的大於等於0的值)進行初始化。調用await方法將使線程阻塞,直到當前計數(count值)由於countdown方法的調用而達到零,此後所有等待的線程被釋放並且任何後續調用await方法也會立即返回。CountDownLatch被設計爲只觸發一次,即Count值在運行過程中無法重置。如果需要重置計數的版本,可以考慮使用CyclicBarrier.

CountDownLatch是一種通用的同步工具。 CountDownLatch可以被認爲是一個簡單的on/off鎖存器或門:所有線程調用await方法等待開關打開,直到countDown方法被調用打開開關爲止。 創建一個CountDownLatch,指定count的值爲N,那麼這個CountDownLatch對象可以讓一個線程等待其他N個線程結束(調用countDown方法即認爲結束),或者調用了這個CountDownLatch的countDown方法N次。

2-方法的註釋

1-構造器


構造器方法,必須指定count值,且count值不能小於0,註釋的意思:創建CountDownLatch對象時需指定count值,count值即當前線程從調用await方法時處於阻塞狀態轉換到就緒狀態時countDown方法必須調用的次數!

2-await方法

await方法使當前線程等待直到count值爲0,或者當前線程被打斷!如果當前的count值爲0,那麼await方法直接返回,當前線程不會阻塞!如果當前的count值大於0,那麼當前線程阻塞(線程調度機制無法給當前線程分配CPU時間片),直到以下兩種情況任意一種發生爲止:

1-count值通過countDown方法的調用達到0

2-    其他線程打斷了當前線程

3-   countDown方法

當前的count值減一,如果count值爲0則釋放所有等待的線程!如果當前count值大於0,則減一,如果count值爲0,則所有等待的線程對於線程調度機制來說都是活躍的了!

3-代碼說話

創建一個模擬執行任務後調用countDown的任務,代碼如下:

class TaskPortion implements Runnable {

    private static int counter = 0;

    //編號
    private final int id = counter++;

    private static Random random = new Random(47);

    //通過構造器指定CountDownLatch對象
    private final CountDownLatch latch;

    public TaskPortion(CountDownLatch latch) {
        this.latch = latch;
    }

    @Override
    public void run() {
        try {
            //模擬任務的執行
            doWork();
            //任務執行完,將CountDownLatch對象的count值減一
            latch.countDown();
            //打印當前的count值
            System.out.println("Count of Latch:" + latch.getCount());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public void doWork() throws InterruptedException {
        TimeUnit.MILLISECONDS.sleep(random.nextInt(2000));
        System.out.println(this + " completed!");
    }

    public String toString() {
        return String.format("%1$-3d", id);
    }
}

創建一個調用CountDownLatch的await方法的任務:

/**
 * 等待任務
 */
class WaitingTask implements Runnable {

    private static int counter = 0;

    //編號
    private final int id = counter++;

    //通過構造器指定CountDownLatch對象
    private final CountDownLatch latch;

    public WaitingTask(CountDownLatch latch) {
        this.latch = latch;
    }

    @Override
    public void run() {
        try {
            //如果count>0阻塞,count=0直接執行
            latch.await();
            System.out.println("Count of Latch:" + latch.getCount());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

創建測試類,代碼如下:

public class CountDownLatchDemo {

    private static int COUNT = 5;
    private static int LOOP = 4;

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        //創建一個count=5的CountDownLatch對象
        CountDownLatch latch = new CountDownLatch(COUNT);
        //10個WaitingTask阻塞
        for (int i = 0; i < 10; i++) {
            executorService.execute(new WaitingTask(latch));
        }
        /**
         * 如果LOOP<COUNT,latch的countDown方法只會調用4次,程序會阻塞
         */
        for (int i = 0; i < LOOP; i++) {
            executorService.execute(new TaskPortion(latch));
        }
        System.out.println("Latched all tasks!");
        executorService.shutdown();
    }

}

在測試代碼中,首先初始化了一個CountDownLatch對象,其count值爲COUNT,然後在線程池中添加了10條調用await方法的任務,10條任務阻塞,然後在線程池中添加了LOOP條調用了CountDownLatch實例的countDown方法的任務,每執行一個任務CountDownLatch對象的count值減一。可知如果LOOP<COUNT那麼CountDownLatch對象的count值永遠不會爲0,那麼程序10條任務就會一直等待,程序就一直阻塞!反之,如果LOOP>=COUNT,那麼CountDownLatch實例的count值就會變成0,從而10條阻塞的任務就會釋放!

當把測試代碼中的LOOP改成5後,再次執行,打印結果如下:

Latched all tasks!
1   completed!
Count of Latch:4
2   completed!
Count of Latch:3
4   completed!
Count of Latch:2
0   completed!
Count of Latch:1
3   completed!
Count of Latch:0
Count of Latch:0
Count of Latch:0
Count of Latch:0
Count of Latch:0
Count of Latch:0
Count of Latch:0
Count of Latch:0
Count of Latch:0
Count of Latch:0
Count of Latch:0
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章