CountDownLatch介绍

java.util.concurrent.CountDownLatch

 

介绍:

    CountDownLatch是一个开闭锁,允许多个线程同时阻塞在一个点,然后通过信号量来同时释放线程。就好像赛马比赛:所有的马(Thread)都等着栅栏(Singal)放开那一刻,放开后,奋力前行,到达终点(CPU或者其他资源)。

    CountDownLatch初始化方法为:CountDownLatch(int count) ;需要给定一个计数器,这个计数器就是我们预期等待的线程个数。当调用CountDownLatch.await方法时,回去判断这个count是否为0,如果为0了则不会阻塞线程,如果不为0则阻塞。计数器count的值通过Co Latch.countDown()方法来减少。

    1、CountDownLatch可以做并发测试。

    比如:有一个服务UserService.addUser(String name)的流程为:先查询name是否存在,如果存在则返回false,否则返回true。这个接口需要确保当N个线程调用时,只有一个name可以插入。 

   

//这个例子在CountDownLatch的doc中,我只是将其改成具有业务含义的例子。 
 class Driver { 
   void main() throws InterruptedException {
     CountDownLatch startSignal = new CountDownLatch(1); //线程的栅栏,使所有现在都在某个点阻塞。
     CountDownLatch doneSignal = new CountDownLatch(N); //并发数

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

     doSomethingElse();            // do sth
     startSignal.countDown();      // let all threads proceed
     doSomethingElse();
     doneSignal.await();           // wait for all to finish
     assertOnlyOneUserName();      //所有线程都执行完成后,我们需要验证,只有一个Name存在。
   }
}

 //测试中,这个工作线程就是去调用addUser服务的。 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();//所有线程必须等待主线程释放栅栏,释放后N个线程一起去抢占资源。
        doWork();
        doneSignal.countDown(); //N个线程全部完成后,唤醒主线程,让其验证N个线程调用服务后的结果。
      } catch (InterruptedException ex) {} // return;
   }

   void doWork() {
     UserService.addUser(xxx) ; //调用需要并发测试的服务

   }
 }
//以上只是一个简单的控制多个线程同时并发的例子。如果想做更精细的代码段测试,可以通过代码动/态编译技术,植入代码片段,让所有的线程都阻塞,然后通过某个信号量释放所有线程,达到并发目的。

 

    2、CountDownLatch另一个用法可能是多线程中做分片处理(分片任务的实现有很多,CountDownLatch只是一种)。

    

class Driver2 { // ...这个例子来自JDK的doc
   void main() throws InterruptedException {
     CountDownLatch doneSignal = new CountDownLatch(N);
     Executor e = ...

     for (int i = 0; i < N; ++i) // create and start threads
       e.execute(new WorkerRunnable(doneSignal, i));//这里其实是将资源分片,交给worker处理

     doneSignal.await();           // wait for all to finish
   }
 }

 class WorkerRunnable implements Runnable {
   private final CountDownLatch doneSignal;
   private final int i;
   WorkerRunnable(CountDownLatch doneSignal, int i) {
      this.doneSignal = doneSignal;
      this.i = i;
   }
   public void run() {
      try {
        doWork(i);
        doneSignal.countDown();
      } catch (InterruptedException ex) {} // return;
   }

   void doWork() { ... }
 }

 

 

 CountDownLatch是AQS共享锁的一个业务实现类。

 

        public int tryAcquireShared(int acquires) {
            return getState() == 0? 1 : -1;//这个方法主要是为了根据计数器来阻塞线程。
        }

        public boolean tryReleaseShared(int releases) { //如果计数器达到0则释放其他等待线程
            // Decrement count; signal when transition to zero
            for (;;) {
                int c = getState();
                if (c == 0)
                    return false;
                int nextc = c-1;
                if (compareAndSetState(c, nextc))
                    return nextc == 0;
            }
        }
 

 

public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }

 public void countDown() {
        sync.releaseShared(1);
    }

 

你可能感兴趣的:(CountDownLatch)