一,類介紹
這是java.util.concurrent包里的一個同步輔助類,它有兩個主要的常用方法 countDown()方法以及await()方法。在完成一組正在其他線程中執行的操作之前,它允許一個或多個線程一直等待。
這個類可以幫助我們做什么事呢?
二,實例運行
列舉一個場景,三個人賽跑,哨聲一響同時出發,跑到一半時A選手突然覺得拿名次沒什么意思,當最后一名也挺好,然后他就讓B,C先跑到終點,然后自己再跑。
這里我們可以開三個線程模擬三位選手,看看我們怎么通過這兩個重要方法來實現A選手的想法的。
代碼如下,不妨先復制一下,跑起來再說。
public class Sample { /** * 計數器,用來控制線程 * 傳入參數2,表示計數器計數為2 */ private final static CountDownLatch mCountDownLatch = new CountDownLatch(2); /** * A線程類 */ private static class ThreadA extends Thread { @Override public void run() { System.out.println("A選手 出發!"); try { // 會阻塞在這里等待 mCountDownLatch 里的count變為0; // 也就是等待另外的WorkingThread調用countDown() mCountDownLatch.await(); } catch (InterruptedException e) { } System.out.println("A選手 到終點拉!"); } } /** * BC線程類 */ private static class WorkingThread extends Thread { private final String mThreadName; private final int mSleepTime; public WorkingThread(String name, int sleepTime) { mThreadName = name; mSleepTime = sleepTime; } @Override public void run() { System.out.println("[" + mThreadName + "] 出發!"); try { Thread.sleep(mSleepTime); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("[" + mThreadName + "] 到終點拉!"); mCountDownLatch.countDown(); } } public static void main(String[] args) throws Exception { // 最先run ThreadA new ThreadA().start(); new WorkingThread("B選手", 2000).start(); new WorkingThread("C選手", 2000).start(); } }
三,代碼分析
現在我們來分析一下代碼,我們先開啟了A線程,它先跑了,但是在A線程的run方法中,調用了await()方法,這個方法可以讓當前線程處於等待狀態,直到計數器為0時,才繼續往下執行。
好了計數器是什么東西,其實CountDownLatch這個類我們就可以把它看出一個計數器,實際上它內部也真實維護了一個count計數,對計數的操作都是原子的,啰嗦一句,原子操作的意思
就是當一個線程對count進行修改時,其他的線程是不可以同時修改的。上面說到要等到計數器為0才行,顯然想讓它為0,就得有個初始值,然后再有減的操作才行吧。賦初始值的操作,就是new這
個對象的時候就完成拉,代碼中 new CountDownLatch(2) 就是給count設為2的操作,然后mCountDownLatch.countDown()這個方法就是count減去1的操作,代碼我們減了兩次,為0之后,A選手才繼續跑完。
好了,這樣的栗子好像只能幫助理解,但是挑不起興趣,再舉一個工作中真實用到的場景。
開啟多個線程分塊下載一個大文件,每個線程只下載固定的一截,最后由另外一個線程來拼接所有的分段,那么這時候我們可以考慮使用CountDownLatch來控制並發,使得拼接的線程放在最后執行。