我们有些场景,是需要使用 多线各一起执行某些操作的,比如进行并发测试,比如进行多线程数据汇总。   自然,我们可以使用 CountDownLatch, CyclicBarrier, 以及多个 Thread.join()。 虽然最终的效果都差不多,但实际却各有千秋。我们此处主要看 CyclicBarrier .      概要: CyclicBarrier 使用 n 个 permit 进行初始化,当n个线程都到达后进行放行,然后进入下一个循环周期。在放行的同时,还可以设置一个执行方法,即相当于回调操作。 一、CyclicBarrier 具体实现   主循环等待! 复制代码 // CyclicBarrier /** * Main barrier code, covering the various policies. */ private int dowait(boolean timed, long nanos) throws InterruptedException, BrokenBarrierException, TimeoutException { // 使用一个 互斥锁,保证进行排队等待的安全性 final ReentrantLock lock = this.lock; lock.lock(); try { // 使用的一 Generation 代表一生循环周期,当周期到达后,替换此值 final Generation g = generation; // 针对异常情况,直接抛出异常,一般是用于多线程之间通信 if (g.broken) throw new BrokenBarrierException(); if (Thread.interrupted()) { // breakBarrier 是针对其他线程的,而 抛出的 InterruptedException 是针对当前线程的 // 从而达到中断标志全局可见的效果 breakBarrier(); throw new InterruptedException(); } // 以下逻辑为进入了等待区域, count-1, 当减到0之后,就代表需要进行放行了 int index = --count; // 放行 if (index == 0) { // tripped boolean ranAction = false; try { final Runnable command = barrierCommand; // 如果设置了回调,则立即执行回调,在当前线程中 if (command != null) command.run(); ranAction = true; // 循环周期迭代,此操作后,其他所有等待线程都将被返回,进入下一轮周期 nextGeneration(); return 0; } finally { // 未知异常,撤销当前的等待 if (!ranAction) breakBarrier(); } } // loop until tripped, broken, interrupted, or timed out for (;;) { try { // 一直在此处进行等待,直到被唤醒,被唤醒时,则意味着有事件发生了 // 等待中将会释放锁,从而让其他线程进入 // 此处的 await() 是一个复杂的故事,因为它要保证在 notify 时的锁竞争问题 if (!timed) trip.await(); else if (nanos > 0L) nanos = trip.awaitNanos(nanos); } catch (InterruptedException ie) { if (g == generation && ! g.broken) { breakBarrier(); throw ie; } else { // We're about to finish waiting even if we had not // been interrupted, so this interrupt is deemed to // "belong" to subsequent execution. 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(); } } 复制代码   可以看到,主要逻辑就是在于 生命周期的迭代操作,但是这个生命周期的标志异常的简单: 复制代码 // 只有一个标识位, broken 为 true 时,发生了异常,整体退出 private static class Generation { boolean broken = false; } 复制代码   而到达的线程数足够之后,需要进行周期迭代,只是 Generation 更换一个变量,另外就是要起到通知所有等待线程的作用: 复制代码 // CyclicBarrier /** * Updates state on barrier trip and wakes up everyone. * Called only while holding lock. */ private void nextGeneration() { // signal completion of last generation // 先通知等待线程,但此时当前线程仍然持有锁,所以其他线程仍然处理等待状态 // 然后再设置下一周期,直到本线程当前同步块退出之后,其他线程才可以进行工作 // 此处依赖于 ReentrantLock // 此处体现 wait/notify 的锁作用域问题 trip.signalAll(); // set up next generation count = parties; generation = new Generation(); } 复制代码   而调用 入口 仅是调用 dowait() 方法而已. 复制代码 // CyclicBarrier public int await() throws InterruptedException, BrokenBarrierException { try { return dowait(false, 0L); } catch (TimeoutException toe) { throw new Error(toe); // cannot happen } } 复制代码   CyclicBarrier 本身的等待逻辑是简单巧妙的,使用 ReentrantLock 的目的是为了实现带超时等待的效果,否则就是一个 wait/notify 机制的实现。当然 wait/notify 的逻辑还是很关键很复杂的,后续如有必要再写一文说明。   完整代码如下: View Code    二、简单看一下 CountDownLatch 的同时等待实现   CountDownLatch 会在初始化时,申请 n 个 permit, 调用 await() 进行阻塞, 直到 permit=0 时,await() 才进行返回。每调用一次 countDown(); permit 都会减1直到为0止; 复制代码 // CountDownLatch.await() 等待 public void await() throws InterruptedException { // 仅是去尝试获取一个而已 sync.acquireSharedInterruptibly(1); } // CountDownLatch.countDown() 释放锁, 当 permit=0 后,放行 await() public void countDown() { // 此处仅是委托给了 AQS 进行释放、通知处理 sync.releaseShared(1); } // CountDownLatch 内部锁实现的是否可以持有锁的逻辑 /** * Synchronization control For CountDownLatch. * Uses AQS state to represent count. */ 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) { // 只要 state=0, 都可以放行 return (getState() == 0) ? 1 : -1; } // 释放锁 countDown 逻辑, 做减1操作 protected boolean tryReleaseShared(int releases) { // Decrement count; signal when transition to zero for (;;) { int c = getState(); // 如果已经被释放,则直接返回 if (c == 0) return false; // 忽略传入值 releases, 只做减1操作, 所以 state 必定有等于0的时候 int nextc = c-1; if (compareAndSetState(c, nextc)) // 只有等于0, 才能进行真正的释放通知操作 return nextc == 0; } } } 复制代码   可以看出, CountDownLatch 的同时等待实现更加简单,几乎都是依赖于 AQS 进行实现。同样,从实际效果来说,也是一个 wait/notify 的实现。只是此处的 notify 执行完之后就释放了锁,即无法保证 notify 之后的线程安全性。   上面两个工具也都是AQS实现的,由此也可知AQS的重要性!   https://www.cnblogs.com/yougewe/p/11690524.html