源码分析
1 package java.util.concurrent; 2 3 import java.util.concurrent.locks.AbstractQueuedSynchronizer; 4 /* 5 一个同步类工具,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成 CountDownLatch用一个给定的count初始化, 6 await方法会一直阻塞直到调用countDown方法使当前的count值变成0,之后所有等待线程被释放,并且任何后续的await调用立即返回 7 8 CountDownLatch初始化为N可以用来作一个线程等待,直到N个线程完成某项操作,或某些动作已经完成N次 9 10 class Driver { // ... 11 void main() throws InterruptedException { 12 CountDownLatch startSignal = new CountDownLatch(1); 13 CountDownLatch doneSignal = new CountDownLatch(N); 14 15 for (int i = 0; i < N; ++i) // create and start threads 16 new Thread(new Worker(startSignal, doneSignal)).start(); 17 18 doSomethingElse(); // don't let run yet 19 startSignal.countDown(); // let all threads proceed 20 doSomethingElse(); 21 doneSignal.await(); // wait for all to finish 22 } 23 } 24 25 class Worker implements Runnable { 26 private final CountDownLatch startSignal; 27 private final CountDownLatch doneSignal; 28 Worker(CountDownLatch startSignal, CountDownLatch doneSignal) { 29 this.startSignal = startSignal; 30 this.doneSignal = doneSignal; 31 } 32 public void run() { 33 try { 34 startSignal.await(); 35 doWork(); 36 doneSignal.countDown(); 37 } catch (InterruptedException ex) {} // return; 38 } 39 40 void doWork() { ... } 41 } 42 43 另一个典型的用法是把一个问题划分为N个部分,每一个部分用一个线程执行并把所有的线程 44 放在Executor里面排队,执行完成就调用countDown方法,当所有子线程都执行完成,接应 45 线程就可以通过await,即不被CountDownLatch的await方法阻塞了 46 class Driver2 { // ... 47 void main() throws InterruptedException { 48 CountDownLatch doneSignal = new CountDownLatch(N); 49 Executor e = ... 50 51 for (int i = 0; i < N; ++i) // create and start threads 52 e.execute(new WorkerRunnable(doneSignal, i)); 53 54 doneSignal.await(); // wait for all to finish 55 } 56 } 57 58 class WorkerRunnable implements Runnable { 59 private final CountDownLatch doneSignal; 60 private final int i; 61 WorkerRunnable(CountDownLatch doneSignal, int i) { 62 this.doneSignal = doneSignal; 63 this.i = i; 64 } 65 public void run() { 66 try { 67 doWork(i); 68 doneSignal.countDown(); 69 } catch (InterruptedException ex) {} // return; 70 } 71 72 void doWork() { ... } 73 } 74 */ 75 76 // CountDownLatch底层由AQS支持 77 public class CountDownLatch { 78 // 内部类Sync 79 private static final class Sync extends AbstractQueuedSynchronizer { 80 private static final long serialVersionUID = 4982264981922014374L; 81 82 Sync(int count) { 83 setState(count); 84 } 85 86 int getCount() { 87 return getState(); 88 } 89 90 protected int tryAcquireShared(int acquires) { 91 return (getState() == 0) ? 1 : -1; 92 } 93 94 protected boolean tryReleaseShared(int releases) { 95 // Decrement count; signal when transition to zero 96 for (; ; ) { 97 int c = getState(); 98 if (c == 0) 99 return false; 100 int nextc = c - 1; 101 if (compareAndSetState(c, nextc)) 102 return nextc == 0; 103 } 104 } 105 } 106 107 private final Sync sync; 108 109 // 构造一个给定初始化为count的CountDownLatch count是线程能通过await方法之前需要调用countDown方法的次数 110 public CountDownLatch(int count) { 111 if (count < 0) throw new IllegalArgumentException("count < 0"); 112 this.sync = new Sync(count); 113 } 114 115 /* 116 使当前线程在倒计数为零前一直等待,除非线程被中断 117 如果当前count值为0,那么await方法会立即返回 如果当前count值大于0,当前线程会处于休眠状态直到: 118 1.由于调用countDown方法使得count值达到0 2.其他某个线程中断了当前线程 119 如果当前线程在进入await方法时已经设置了中断状态,或者在等待时被中断,则抛出InterruptedException异常,并清除当前线程的已中断状态 120 */ 121 public void await() throws InterruptedException { 122 sync.acquireSharedInterruptibly(1); 123 } 124 125 /* 126 使当前线程在倒计数为零前一直等待,除非线程被中断或超出了指定的等待时间 127 如果当前count值为0,那么await方法会立即返回true 如果当前count值大于0,当前线程会处于休眠状态直到: 128 1.由于调用countDown方法使得count值达到0 2.其他某个线程中断了当前线程 3.已超出指定的等待时间 129 如果计数达到零,那么await(long timeout, TimeUnit unit)会返回true 130 如果当前线程在进入await方法时已经设置了中断状态,或者在等待时被中断,则抛出InterruptedException异常,并清除当前线程的已中断状态 131 如果超出了指定的等待时间,则返回值为false,如果指定时间小于或等于0,那么await(long timeout, TimeUnit unit)根本不会等待,即不会阻塞主线程 132 timeout:要等待的最长时间 unit:timeout参数的时间单位 133 134 如果计数到达零,则返回true 如果在计数到达零之前超过了等待时间,则返回false 135 */ 136 public boolean await(long timeout, TimeUnit unit) 137 throws InterruptedException { 138 return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout)); 139 } 140 141 /* 142 递减闭锁的count值,如果计数到达零,则释放所有等待的线程 143 当前count值大于0,递减 当前count等于0,被阻塞的线程可以被调度了,且count值不会递减了 144 */ 145 public void countDown() { 146 sync.releaseShared(1); 147 } 148 149 public long getCount() { 150 return sync.getCount(); 151 } 152 153 public String toString() { 154 return super.toString() + "[Count = " + sync.getCount() + "]"; 155 } 156 }
典型用法
1 package test; 2 3 import java.util.Random; 4 import java.util.concurrent.CountDownLatch; 5 6 /* 7 CountDownLatch允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行 8 count:初始化count数表示子线程计数器,只有为0时,主线程才会向下执行 9 countDown()方法:计数器的值-1,如果计数达到0,释放所有等待的线程 10 await()方法:使主线程等到计数器为0才执行 11 12 马拉松比赛,对参赛者的排名肯定是在所有参赛者跑完比赛之后进行,即N个线程执行操作,主线程等到N个子线程执行完毕之后再执行 13 */ 14 public class CountDownLatchTest { 15 public static void main(String[] args) throws InterruptedException { 16 int threadCount = 10; 17 final CountDownLatch latch = new CountDownLatch(threadCount); 18 19 for (int i = 0; i < threadCount; i++) { 20 new Thread(new Runnable() { 21 @Override 22 public void run() { 23 System.out.println("线程" + Thread.currentThread().getId() + "开始出发"); 24 try { 25 Thread.sleep(new Random().nextInt(1000)); 26 } catch (InterruptedException e) { 27 e.printStackTrace(); 28 } 29 System.out.println("线程" + Thread.currentThread().getId() + "已到达终点"); 30 latch.countDown(); 31 } 32 }).start(); 33 } 34 latch.await(); 35 System.out.println("所有线程已经执行完毕,开始计算排名"); 36 } 37 38 }