天天看點

【JUC系列第四篇】-CountDownLatch使用場景分析

作者 : 畢來生

前言

​ 在 java.util.concurrent 包中提供了多種并發容器類來改進同步容器 的性能。今天我們來聊一聊CountDownLatch 的使用場景。看看它到底是怎麼玩耍的。

CountDownLatch 是幹什麼的?

​ CountDownLatch 一個同步輔助類,在完成一組正在其他線程中執行的操作 之前,它允許一個或多個線程一直等待。

CountDownLatch原理

​ CountDownLatch是通過一個計數器來實作的,計數器的初始化值為線程的數量。每當一個線程完成了自己的任務後,計數器的值就相應得減1。當計數器到達0時,表示所有的線程都已完成任務,然後在閉鎖上等待的線程就可以恢複執行任務。

使用場景

​ 在某些業務情況下,要求我們等某個條件或者任務完成後才可以繼續處理後續任務。同時線上程完成時也會觸發一定事件。友善業務繼續向下執行。這個時候我們的CountDownLatch就隆重登場啦。常用核心方法為

/**
     * 遞減計數器的計數,如果計數達到0,則釋放所有等待的線程。
     * 如果目前計數大于0,則将計數減少。
     * 如果新的計數為0,會重新開機所有等待線程
     * 如果目前計數等于0,則不做任何操作
     **/
    public void countDown() {
        sync.releaseShared(1);
    }
    /**
     * 1、目前線程在倒數至0之前會一直等待
     * 2、除非線程被中斷或超出了指定的時間。
     * 3、如果目前計數為0,立刻傳回為true
     * 4、如果目前計數等于0,則不做任何操作
     * 5、如果目前線程在進入此方法時已經設定了該線程的中斷狀态,
     *      或者在等待時被中斷,則抛出InterruptedException
     **/
    public boolean await(long timeout, TimeUnit unit)
            throws InterruptedException {
        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    }           

實戰演練

package org.bilaisheng.juc;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @Author: bilaisheng
 * @Wechat: 878799579
 * @Date: 2019/1/2 23:30
 * @Todo: CountDownLatch demo。
 * @Version : JDK11 , IDEA2018
 */
public class CountDownLatchTest {

    // 舉個例子:有十個毒販在和警察激戰
    public static void main(String[] args) throws InterruptedException {

        // 開始計數器
        final CountDownLatch start = new CountDownLatch(1);
        // 結束計數器
        final CountDownLatch end = new CountDownLatch(10);

        final ExecutorService executorService = Executors.newFixedThreadPool(10);

        for (int i = 1; i <= 10; i++) {
            // 這個變量純粹為了掩飾到底哪個倒黴先被幹掉。
            final String criminal = "第"+i+"個毒販";
            Runnable task = new Runnable() {
                @Override
                public void run() {
                    try {
                        // 如果目前已經沒有可以毒販,立刻傳回
                        start.await();
                        Thread.sleep(500);
                        System.out.println(criminal + "被幹掉了!");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    } finally {
                        // 幹掉一個。毒販活着的數量就減1
                        end.countDown();
                    }
                }
            };
            executorService.submit(task);
        }

        // 抓捕開始
        start.countDown();
        //  全都被幹掉了(計數器為0)
        end.await();
        // 任務完成:收工回家
        executorService.shutdown();
    }
}
           
【JUC系列第四篇】-CountDownLatch使用場景分析

閉鎖可以延遲線程的進度直到其到達終止狀态,閉鎖可以用來確定某些活動直到其他活動都完成才繼續執行:

  • 確定某個計算在其需要的所有資源都被初始化之後才繼續執行;
  • 確定某個服務在其依賴的所有其他服務都已經啟動之後才啟動;
  • 等待直到某個操作所有參與者都準備就緒再繼續執行。

喜歡就關注我吧

【JUC系列第四篇】-CountDownLatch使用場景分析