1. 程式人生 > >java併發程式設計之使用 CountDownLatch 控制多個執行緒執行順序

java併發程式設計之使用 CountDownLatch 控制多個執行緒執行順序

有時候會有這樣的需求,多個執行緒同時工作,然後其中幾個可以隨意併發執行,但有一個執行緒需要等其他執行緒工作結束後,才能開始。舉個例子,開啟多個執行緒分塊下載一個大檔案,每個執行緒只下載固定的一截,最後由另外一個執行緒來拼接所有的分段,那麼這時候我們可以考慮使用CountDownLatch來控制併發。

    CountDownLatch是JAVA提供在java.util.concurrent包下的一個輔助類,可以把它看成是一個計數器,其內部維護著一個count計數,只不過對這個計數器的操作都是原子操作,同時只能有一個執行緒去操作這個計數器,CountDownLatch通過建構函式傳入一個初始計數值,呼叫者可以通過呼叫CounDownLatch物件的cutDown()方法,來使計數減1;如果呼叫物件上的await()方法,那麼呼叫者就會一直阻塞在這裡,直到別人通過cutDown方法,將計數減到0,才可以繼續執行。

示例

import java.util.concurrent.CountDownLatch;

public class Sample {
    /**
     * 計數器,用來控制執行緒
     * 傳入引數2,表示計數器計數為2
     */
    private final static CountDownLatch mCountDownLatch = new CountDownLatch(2);

    /**
     * 示例工作執行緒類
     */
    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 + "] started!");
            try {  
                    Thread.sleep(mSleepTime);  
            } catch (InterruptedException e) {  
                    e.printStackTrace();  
            }
            mCountDownLatch.countDown();
            System.out.println("[" + mThreadName + "] end!"); 
        }
    }
    
    /**
     * 示例執行緒類
     */
    private static class SampleThread extends Thread {
        
        @Override
        public void run() {
            System.out.println("[SampleThread] started!");
            try {
                // 會阻塞在這裡等待 mCountDownLatch 裡的count變為0;
                // 也就是等待另外的WorkingThread呼叫countDown()
                mCountDownLatch.await();
            } catch (InterruptedException e) {
                
            }
            System.out.println("[SampleThread] end!");
        }
    }
    
    public static void main(String[] args) throws Exception {
        // 最先run SampleThread
        new SampleThread().start();
        // 執行兩個工作執行緒
        // 工作執行緒1執行5秒
        new WorkingThread("WorkingThread1", 5000).start();
        // 工作執行緒2執行2秒
        new WorkingThread("WorkingThread2", 2000).start();
    }
}

執行結果:

[SampleThread] started!
[WorkingThread1] started!
[WorkingThread2] started!
[WorkingThread2] end!
[WorkingThread1] end!
[SampleThread] end!

達到了目的。當然還有其他方式可以做到這樣的效果,本文僅僅是介紹了一種使用CountDownLatch的方式。