CountDownLatch
它主要是用在保证主线程要在多个线程运行完之后再次运行的,并且它也是根据AQS来实现的,当初始化的时候,它传入的值其实是赋予给了AQS中的state变量,然后主线程调用await方法后,就会阻塞,当state变量变为0时候然后才会被唤醒,而使得state变量减小的操作就是CountDown方法。
CycliBarrier
它顾名思义,也就是一种栅栏,它主要是用来保证多个线程全部到达一个状态后,然后这些线程才能继续往下执行。之前看到很多人说它其实是使用加法,但是后面自己看了源码后才发现,它其实也是依靠减法,对一个count计数器进行减小,当减到0的时候,则是会让这些调用await的线程继续往下执行。
CycliBarrier源码
其中最主要的是它的await方法,而这个await方法中真正工作的则是这个await方法。如下图所示的
int index = --count;它则是对计数器来做一个减法,当减到0的时候则是会执行一个nextGeneration();和一个breakBarrier();这个方法,其中breakBarrier();是用来唤醒所有线程的,它其实是调用了signalAll()这个方法,nextGeneration()它则是用来将计数器恢复为初始值,来供我们再次使用。
private int dowait(boolean timed, long nanos) throws InterruptedException, BrokenBarrierException, TimeoutException { final ReentrantLock lock = this.lock; lock.lock(); try { final Generation g = generation; if (g.broken) throw new BrokenBarrierException(); if (Thread.interrupted()) { breakBarrier(); throw new InterruptedException(); } 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 { 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(); } }
二者的区别总结:
1. CycliBarrier它主要是用来让多个线程运行到一定的状态后,然后再次执行。而CountDownLatch则是让主线程等待其他线程调用了CountDown方法后才能继续执行。
2. CountDown它是不可以被重复使用的,而CycliBarrier它则是被可以重复使用的
3. CountdownLatch利用继承AQS的共享锁来进行线程的通知,利用CAS来进行--,而CyclicBarrier则利用ReentrantLock的Condition来阻塞和通知线程