一入君,深似海,从此对象为路人。观众们好,你们好,我的战神吕布,叫做奉贤。今天就给大家来一段吕布的教学视频!咳咳,这是错误的。大家好,我是雷哥,今天给大家带来一篇关于CountDownLatch的文章。在开始之前,我想问大家一个很专业的技术问题:团战中最怕_____的是什么?送分是一道很简单的题。如果答错了,雷哥会批评你的,哈哈。可能有人会说:团战最怕猪队友,但是比猪队友更可怕的是团战人手不够。兄弟,你想想如果是5V2团战会是什么感觉。痛得不敢想。🤦🏻??。等着别人齐在坦雷哥在儿子出生前也是一名资深农药师。至于军衔?不要问!问是青铜。雷师兄的级别虽然不是很高,但对大局还是有基本的看法的。毕竟他也是玩了几年dota和LOL的青铜选手吧?哈哈。杀虫剂和其他moba游戏一样。想要赢,就必须把握好每一场团战,而每一场团战的关键就是要等所有人都齐了再开团不是吗?而这个思路也正是我们要讲的CountDownLatch的思路,我们来看看是怎么回事。我有Admiral"CountDownLatch"想象一下这样一个场景,当我们需要等待一些线程执行完,然后执行主线程的代码,如何实现呢?可能有人会说,简单吧,使用join()方法,等待线程执行完成后,执行主线程即可。实现代码如下://创建线程1Threadt1=newThread(newRunnable(){@Overridepublicvoidrun(){//dosomething}});t1.start();//创建线程2Threadt2=newThread(newRunnable(){@Overridepublicvoidrun(){//dosomething}});t2.start();//等待线程1和线程2执行完毕t1.join();t2.join();当然,如果使用Thread来执行任务,那么这种写法也是可行的。但是在真实的(编码)环境中,我们不会使用Thread来进行多任务处理,而是会使用线程池来进行多任务处理,这样可以避免线程重复启动和销毁带来的性能开销。实现代码如下://创建固定线程数的线程池ExecutorServiceexecutorService=Executors.newFixedThreadPool(2);//Task1executorService.submit(newRunnable(){@Overridepublicvoidrun(){//dosomething}});//任务2executorService.submit(newRunnable(){@Overridepublicvoidrun(){//dosomething}});那么这个时候问题就来了,线程池没有join()方法,那么如何实现等待呢?这时候,我们就送上我们通用的“CountDownLatch”啦。我有潘凤将军,能杀华雄……几秒,潘凤……“死”。等等导演,我觉得剧情应该是这样的……CountDownLatch用来实现等待所有线程池执行完毕后,再执行主线程的逻辑。我决定使用AQS下著名的类CountDownLatch(AbstractQueuedSynchronizer,抽象同步框架)来实现这个功能的具体实现代码如下:publicstaticvoidmain(String[]args)throwsInterruptedException{//CreateCountDownLatchCountDownLatchcountDownLatch=newCountDownLatch(2);//创建一个固定线程数的线程池ExecutorServiceexecutorService=Executors.newFixedThreadPool(2);//任务1executorService.submit(newRunnable(){@Overridepublicvoidrun(){//dosomethingtry{//让这个任务执行1.2sThread.sleep(1200);}catch(InterruptedExceptione){e.printStackTrace();}System.out.println("我是任务一");countDownLatch.countDown();}});//任务二executorService.submit(newRunnable(){@Overridepublicvoidrun(){//dosomethingtry{//让这个任务执行1.2sThread.sleep(1000);}catch(InterruptedExceptione){e.printStackTrace();}System.out.println("我是任务二");countDownLatch.countDown();}});//等待任务执行到completecountDownLatch.await();System.out.println("程序执行完成~");}上面程序的执行结果如下:从上面的结果我们可以看出主线程的执行等待任务1和任务2的执行要完成。CountDownLatch的实现原理在CountDownLatch中,countdown表示倒计时,latch表示锁存器。整体意思可以理解为一个倒计时的闩锁,好像有点像“321,芝麻开门”,CountDownLatch的功能完全一样。在创建CountDownLatch时,需要传入一个整数,在整数“倒计时”到0之前,主线程需要挂起,等待所有其他线程执行完毕,主线程才能继续执行。CountDownLatch执行过程CountDownLatch的实现是在其内部创建并维护一个volatile整型计数器。当调用countDown()方法时,它会尝试将整数计数器设置为-1。当wait()方法被调用时,当前线程会判断整数计数器是否为0,如果为0则继续执行,如果不为0则使当前线程进入等待状态,直到有线程设置计数器为0,会唤醒等待在await()方法中的线程继续执行。CountDownLatch的常用方法//线程被挂起,直到计数值为0后才继续执行publicvoidawait()throwsInterruptedException{};//类似于await(),但如果计数值没有变为0则继续执行等待一定时间后执行publicbooleanawait(longtimeout,TimeUnitunit)throwsInterruptedException{};//计数值减1publicvoidcountDown(){};总结使用CountDownLatch可以实现等待所有任务执行完之前的功能执行主要任务。就好像在比赛中等待所有的运动员等所有人都打完之后再发名次一样。当然,我们在打农药的时候也是一样的。得等大家齐齐,才能组队。这是取胜的关键。CountDownLatch通过计数器实现等待功能。创建CountDownLatch时,会设置一个大于0的计数器,每次调用countDown()方法时,计数器的值为-1。当计数器值变为0时,等待任务将可以继续执行。参考与致谢www.jianshu.com/p/128476015902
