1. 程式人生 > >C# implement java like CountDownLatch

C# implement java like CountDownLatch

CountDownLatch是在java1.5被引入的,跟它一起被引入的併發工具類還有CyclicBarrier、Semaphore、ConcurrentHashMapBlockingQueue,它們都存在於java.util.concurrent包下。CountDownLatch這個類能夠使一個執行緒等待其他執行緒完成各自的工作後再執行。例如,應用程式的主執行緒希望在負責啟動框架服務的執行緒已經啟動所有的框架服務之後再執行。

CountDownLatch是通過一個計數器來實現的,計數器的初始值為執行緒的數量。每當一個執行緒完成了自己的任務後,計數器的值就會減1。當計數器值到達0時,它表示所有的執行緒已經完成了任務,然後在閉鎖上等待的執行緒就可以恢復執行任務。

CountDownLatch的虛擬碼如下所示:

//Main thread start
//Create CountDownLatch for N threads
//Create and start N threads
//Main thread wait on latch
//N threads completes there tasks are returns
//Main thread resume execution

CountDownLatch如何工作

CountDownLatch.java類中定義的建構函式:

//Constructs a CountDownLatch initialized with the given count.
public void CountDownLatch(int count) {...}

構造器中的計數值(count)實際上就是閉鎖需要等待的執行緒數量。這個值只能被設定一次,而且CountDownLatch沒有提供任何機制去重新設定這個計數值

與CountDownLatch的第一次互動是主執行緒等待其他執行緒。主執行緒必須在啟動其他執行緒後立即呼叫CountDownLatch.await()方法。這樣主執行緒的操作就會在這個方法上阻塞,直到其他執行緒完成各自的任務。

其他N 個執行緒必須引用閉鎖物件,因為他們需要通知CountDownLatch物件,他們已經完成了各自的任務。這種通知機制是通過 CountDownLatch.countDown()

方法來完成的;每呼叫一次這個方法,在建構函式中初始化的count值就減1。所以當N個執行緒都調 用了這個方法,count的值等於0,然後主執行緒就能通過await()方法,恢復執行自己的任務。

在實時系統中的使用場景

讓我們嘗試羅列出在java實時系統中CountDownLatch都有哪些使用場景。我所羅列的都是我所能想到的。如果你有別的可能的使用方法,請在留言裡列出來,這樣會幫助到大家。

  1. 實現最大的並行性:有時我們想同時啟動多個執行緒,實現最大程度的並行性。例如,我們想測試一個單例類。如果我們建立一個初始計數為1的CountDownLatch,並讓所有執行緒都在這個鎖上等待,那麼我們可以很輕鬆地完成測試。我們只需呼叫 一次countDown()方法就可以讓所有的等待執行緒同時恢復執行。
  2. 開始執行前等待n個執行緒完成各自任務:例如應用程式啟動類要確保在處理使用者請求前,所有N個外部系統已經啟動和運行了。
  3. 死鎖檢測:一個非常方便的使用場景是,你可以使用n個執行緒訪問共享資源,在每次測試階段的執行緒數目是不同的,並嘗試產生死鎖。

 

Then we will implement a C# version coudown latch as follows:

    class CountDownLatch
    {
        private object lockObj = new Object();
        private int counter;
 
        public CountDownLatch(int counter)
        {
            this.counter = counter;
        }
 
        public void Await()
        {
            lock (lockObj)
            {
                while (counter > 0)
                {
                    Monitor.Wait(lockObj);
                }
            }
        }
 
        public void CountDown()
        {
            lock (lockObj)
            {
                counter--;
                Monitor.PulseAll(lockObj);
            }
        }
    }

 

An the useage of this class like:

public static void Main(int argc ,string[] argv)
{
    int threadCount = 100;
    CountDownLatch latch = new CountDownLatch(threadCount);
    object state = new object();
    for (int i = 0; i < threadCount; i++)
    {
        ThreadPool.QueueUserWorkItem(new WaitCallback(new WasteTimeTask(latch).DoSth), state);
    }
    latch.Await();
    //全部執行緒執行完成, 繼續
}

public class WasteTimeTask
{
    private CountDownLatch latch;

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

    public void DoSth(object state)
    {
        //模擬耗時操作
        System.Threading.Thread.Sleep(new Random().Next(5) * 1000);
        //執行完成注意呼叫CountDown()方法
        this.latch.CountDown();
    }
}