CountDownLatch:
功能:是一个同步工具类 ,它允许一个或多个线程一直等待(通过调用await进入),直到其他线程的操作执行完(调用countDown)后再唤醒继续执行。
CountDownLatch维护一个状态 count值,这个值可以通过调用countDown 方法让它递减,直到为0
在count为0之前,所有调用await的方法全部挂起。
内部实现:依赖于AbstractQueuedSynchronizer 框架,让调用await的方法的线程挂起park,直到countDown 操作,改变count的值,unpark 对应的线程。
应用场景:
比如一个A服务,需要调用B,C两个服务 并merge他们的结果进行返回
1、A服务线程要进入等待状态(await)
2、通过对B,C各启动一个线程去执行,执行完后(调用countDown),唤醒A
public static void main(String[] args) throws Exception { final CountDownLatch cdl = new CountDownLatch(1); new Thread("A"){ public void run() { try { System.out.println("Thread A entered"); cdl.await(); System.out.println("Thread A over"); } catch (InterruptedException e) { e.printStackTrace(); } }; }.start(); new Thread("B"){ public void run() { try { System.out.println("Thread B entered"); cdl.await(); System.out.println("Thread B over"); } catch (InterruptedException e) { e.printStackTrace(); } }; }.start(); new Thread("C"){ public void run() { System.out.println("Thread C entered"); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } cdl.countDown(); System.out.println("Thread C over"); }; }.start(); }
演化场景:
比赛的时候 多个选手,等待号令
选手:多个选手各自await
号令:countDown,注意Count设置为1
特殊:
1、如果countDown被提前调用了,await 被后调用,结果会如何?
private static void testBasic2() throws Exception{ CountDownLatch cdl = new CountDownLatch(1); cdl.countDown(); cdl.await(); cdl.await(); System.out.println("over"); }
结论:没有影响
2、如果count设置为0,await操作会如何?
private static void testBasic() throws Exception{ CountDownLatch cdl = new CountDownLatch(0); System.out.println(cdl.getCount()); cdl.await(); cdl.await(); System.out.println("over"); }
结论:无法起到线程阻塞的效果
CyclicBarrier:
效果:当多个线程达到齐(await),执行一个操作(Runnable)
内部实现:
1、通过ReentrantLock 实现锁的功能,通过ReentrantLock.newCondition() 进行协调线程
2、通过lock 控制 一个count状态,当一个线程调用CyclicBarrier.await的时候,count 减一,当count=0的时候,执行Runnable.run 方法,并调用signalAll 方法,唤醒其他线程;当count !=0的时候,调用Condition.await 方法,让当前线程挂起。
CyclicBarrier 和CountDownLatch:
CyclicBarrier:是线程到达齐后,开始执行某一个任务,并且是可以循环的
CountDownLatch:更倾向于 某个或者多个线程触发了某个条件,其他线程(一个/多个)可以继续执行下面的任务。