前言 CountDownLatch的主要用途是同步一个或多个任务,使得这些任务在继续执行前必须等待其他任务完成。从类图上可以看到它的内部很简单,只有一个Sync的内部类。其中Sync是继承了AQS的,这意味着CountDownLatch底层还是基于AQS实现的。注意的是CountDownLatch只能等待countDown()前面的逻辑,countDown()后面的逻辑可能会在await()方法后执行,要看系统的调度。
小demo 在这个例子中,我们创建了一个初始计数值为2的CountDownLatch。然后,我们创建了两个线程,每个线程在完成其任务后都会调用countDown()方法。主线程调用await()方法,等待所有其他线程完成任务。当所有其他线程都调用了countDown()方法,计数器的值变为0,主线程才会继续执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public class CountDownLatchTest { public static void main (String[] args) throws InterruptedException { CountDownLatch latch = new CountDownLatch (2 ); new Thread (()->{ selfSleep(200 ); System.out.println("Thread 1 started" ); System.out.println("Thread 1 finished" ); latch.countDown(); }).start(); new Thread (()->{ selfSleep(300 ); System.out.println("Thread 2 started" ); System.out.println("Thread 2 finished" ); latch.countDown(); }).start(); latch.await(); System.out.println("All threads finished" ); } private static void selfSleep (int i) { try { Thread.sleep(i); } catch (InterruptedException e) { throw new RuntimeException (e); } } }
执行结果:
Thread 1 started Thread 1 finished Thread 2 started Thread 2 finished All threads finished
关键属性 只有一个Sync属性,但是这个Sync是CountDownLatch的核心,我们看下它的内部实现
1 private final Sync sync;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 private static final class Sync extends AbstractQueuedSynchronizer { private static final long serialVersionUID = 4982264981922014374L ; Sync(int count) { setState(count); } int getCount () { return getState(); } protected int tryAcquireShared (int acquires) { return (getState() == 0 ) ? 1 : -1 ; } protected boolean tryReleaseShared (int releases) { for (;;) { int c = getState(); if (c == 0 ) return false ; int nextc = c - 1 ; if (compareAndSetState(c, nextc)) return nextc == 0 ; } } }
构造器 构造一个指定倒计数值的CountDownLatch
1 2 3 4 public CountDownLatch (int count) { if (count < 0 ) throw new IllegalArgumentException ("count < 0" ); this .sync = new Sync (count); }
关键方法 countDown() 使倒计数减1,tryReleaseShared(arg)方法会将倒计数减1,如果减成0则返回true,同时唤醒主线程,否则返回false,流程结束。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 public void countDown () { sync.releaseShared(1 ); } public final boolean releaseShared (int arg) { if (tryReleaseShared(arg)) { signalNext(head); return true ; } return false ; } protected boolean tryReleaseShared (int releases) { for (;;) { int c = getState(); if (c == 0 ) return false ; int nextc = c - 1 ; if (compareAndSetState(c, nextc)) return nextc == 0 ; } }
await() 如果倒计数值不为0,释放掉当前线程持有的锁,并将自己加入到等待队列中去,否则说明其它线程已处理完毕,直接执行后续逻辑即可。
1 2 3 4 5 6 7 8 9 10 11 public void await () throws InterruptedException { sync.acquireSharedInterruptibly(1 ); } public final void acquireSharedInterruptibly (int arg) throws InterruptedException { if (Thread.interrupted() || (tryAcquireShared(arg) < 0 && acquire(null , arg, true , true , false , 0L ) < 0 )) throw new InterruptedException (); }