code_money_guji's Blog

Happy coding

CountDownLatch

参考资料:

        林昊  -----<<分布式java应用 基础与实践>>

       JDK api 文档

 

CountDownLatch 功能:

 其用的是一个减数机制, 首先调用new CountDownLatch(int N)构造一个CountDownLatch,注意,CountDownLatch是一次性的,他并不提供任何api给开发者去改变N的大小.线程调用countDownLatch.await()以后, 会进入阻塞状态, 等待其他线程调用countDownLatch.countDown()来完成N-1的操作,并且只有N=0的时候,所有因为调用countDownLatch.await()的线程才能被释放.

下面给出CountdownLatch在JDK文档中的示例程序:

class Driver { // ...
   void main() throws InterruptedException {
     CountDownLatch startSignal = new CountDownLatch(1);//计数器设置为一,是一个开关操作即便是Worker有N个,
                                                                                      //也照样会在调用startSignal.sawait是阻塞.

     CountDownLatch doneSignal = new CountDownLatch(N);//计数器设置为N

     for (int i = 0; i < N; ++i) // create and start threads
       new Thread(new Worker(startSignal, doneSignal)).start();

     doSomethingElse();            // don't let run yet这里是先让线程执行run()方法中的startSignal.await();
     startSignal.countDown();      // let all threads proceed当所有
     doSomethingElse();
     doneSignal.await();           // wait for all to finish
   }
 }

 class Worker implements Runnable {
   private final CountDownLatch startSignal;
   private final CountDownLatch doneSignal;
   Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
      this.startSignal = startSignal;
      this.doneSignal = doneSignal;
   }
   public void run() {
      try {
        startSignal.await();
        doWork();
        doneSignal.countDown();//只有N个线程都执行到此步骤的时候
} catch (InterruptedException ex) {} // return;
   }

   void doWork() { ... }
 }

上述的程序一共是N+1个线程在执行, 可以理解为主线程将一个比较苦难的问题交给N个工作者线程完成. 但是,具体要求是:

1 N个工作者线程需要等待主线程完成好准备工作: startSignal.await()来表示阻塞工作者;Main中的doSomeThingElse()表示主线程准备问题;Main中的startSignalCountDown表示问题准备好了,可以让工作者执行问题;

2 N个工作者线程每一个完成一部分,只有N个线程都完成了各自的工作才能把工作的结果交换给主线程并检查器结果正确性.run中的doneSignal.countDown()以及CountDownLatch doneSignal = new CountDownLatch(N)可以说明这个需求;

 

CoundownLatch countDown方法使用内部类Sync来实现. Sync则是继承自AbstractQueuedSynchronizer. AbstractQueuedSynchronizer在内部是通过维护一个state变量来表示控制的数量.

countDown()方法的实现:

 sync.releaseShared(1);

 sync.releaseShared方法的实现则是通过无所算法CAS(Compare and set) 通过CAS指令来完成乐观操作:

 public boolean tryReleaseShared(int releases) {
            // Decrement count; signal when transition to zero
            for (;;) {
                int c = getState();//获取AbstractQueuedSynchronizer中的state变量.
                if (c == 0)
                    return false;
                int nextc = c-1;
                if (compareAndSetState(c, nextc)) //使用轮询的方式来完成状态的设置.
                    return nextc == 0;
            }
        }
    }

to be continue...