1.CountDownLatch是1个线程等待另外多个线程,主线程要等待,其他线程可以继续做其他事情。
CyclicBarrier是多个线程互相等待,都不能做其他事情。
2.CountDownLatch不能重置,用一次就丢弃。
CyclicBarrier可以通过reset重置。
CyclicBarrier源码解析
CyclicBarrier是通过显示锁ReentrantLock来锁存对象
/** The lock for guarding barrier entry */ private final ReentrantLock lock = new ReentrantLock(); /** Condition to wait on until tripped */ private final Condition trip = lock.newCondition();
核心方法await()
private int dowait(boolean timed, long nanos) throws InterruptedException, BrokenBarrierException, TimeoutException { final ReentrantLock lock = this.lock; lock.lock(); try { final Generation g = generation;//主要用于判断barrier是否被破坏 if (g.broken) throw new BrokenBarrierException(); if (Thread.interrupted()) { breakBarrier(); throw new InterruptedException(); } int index = --count;//每有一个线程通过,index就会自减。 if (index == 0) { // tripper跳出等待。 boolean ranAction = false; try { final Runnable command = barrierCommand; if (command != null)//如果barrier构造的时候,附带一个Runnable,可以用于计时器 command.run(); ranAction = true; nextGeneration();//其他所有线程的唤醒在这里。! return 0; } finally { if (!ranAction) breakBarrier(); } } //循环等待,直到跳出,中断,或者barrier被破坏。 for (;;) { try { if (!timed) trip.await();//lock显示锁里的await方法。 else if (nanos > 0L)//如果设置了等待时间。 nanos = trip.awaitNanos(nanos); } catch (InterruptedException ie) { if (g == generation && ! g.broken) { breakBarrier(); throw ie; } else { // 一个弥补的解决方法,确保线程完全中断。 Thread.currentThread().interrupt(); } } if (g.broken) throw new BrokenBarrierException(); if (g != generation) return index; if (timed && nanos 0L) { breakBarrier(); throw new TimeoutException(); } } } finally { lock.unlock(); } }
barrier的步骤。n-1个线程进去await方法后,都在for(;;)等待。
直到最后一个线程进入await后,将其他所有线程唤醒。
CountDownLatch使用了AbstractQueuedSynchronizer作为辅助类,这是一个适用于所有使用int值作为state状态量的同步辅助类。
并且重写了
protected int tryAcquireShared(int acquires) { return (getState() == 0) ? 1 : -1; } protected boolean tryReleaseShared(int releases) { // Decrement count; signal when transition to zero for (;;) { int c = getState(); if (c == 0) return false; int nextc = c-1;//使计数器减一 if (compareAndSetState(c, nextc))//本地CAS方法,刷新state的值 return nextc == 0; } }
值得一提的是,如果不重写这2个方法,或抛出UnsupportedOperationException();因为在父类中如下定义
protected boolean tryReleaseShared(int arg) { throw new UnsupportedOperationException(); }
跟abstract方法相比,这个非强制的,并且捕获的是一个RuntimeException
第一个核心方法countDown()主要是在上面那个方法中
if (compareAndSetState(c, nextc)) return nextc == 0;
这段调用了一个Unsafe的本地CAS方法(CompareAndSet)
使计数器state减1.
第二个核心方法await()是在AbstractQueuedSynchronizer类中doAcquireSharedInterruptibly(int arg)
private void doAcquireSharedInterruptibly(int arg) throws InterruptedException { final Node node = addWaiter(Node.SHARED);//把主线程添加到等待队列,下面有详细讲解 boolean failed = true; try { for (;;) {//循环等待,阻塞主线程。 final Node p = node.predecessor();//获得节点node的前继 if (p == head) {//确保前继是头节点。 int r = tryAcquireShared(arg);//判断计数器,如果计数器state=0 那么会返回1; if (r >= 0) { setHeadAndPropagate(node, r);//唤醒主线程 p.next = null; // help GC failed = false; return; } } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) throw new InterruptedException(); } } finally { if (failed) cancelAcquire(node); } } private Node addWaiter(Node mode) { Node node = new Node(Thread.currentThread(), mode);//一个构造方法,把主线程添加到等待队列,后继是一个共享节点 // 尝试直接把node节点设置为尾节点, Node pred = tail; if (pred != null) { node.prev = pred; if (compareAndSetTail(pred, node)) { pred.next = node; return node; } } enq(node);//主要是初始化头节点,并且把node设置为尾节点。 return node; } private Node enq(final Node node) { for (;;) { Node t = tail; if (t == null) { // Must initialize if (compareAndSetHead(new Node()))//初始化头节点和尾节点 tail = head; } else { node.prev = t; if (compareAndSetTail(t, node)) {//尾节点设置为node t.next = node;//设置node为头节点的后继。注意此时t指向的是head. return t; } } } }