CountDownLatch是由java并发包提供的一个同步计数器,从字面意义上去理解可以分成两部分CountDown 和 Latch,CountDown就是计数的意思,Latch是门闩,这个同步工具就是通过保证多线程环境下,通过门闩限制主线程执行,子线程执行后计数减1,直到减为0,门闩打开,主线程执行。
场景一:主任务等待其它子任务完成后再执行。
背景:电影院等待所有人都到齐了还开始播放电影,有一个电影院的类为主线程,看电影的人为子线程,假设电影院能容纳5人看电影,下面的类将利用CountDownLatch实现该功能。
public class Cinema { public static void main(String[] args) { CountDownLatch countDownLatch = new CountDownLatch(5); ExecutorService executor = Executors.newFixedThreadPool(3); for(int i=0; i<5; i++){ executor.execute(new Person(countDownLatch)); } System.out.println("电影院等待人入场..."); //阻塞当前线程,直到计数器的值为0 try { countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("人已到齐,开始播放电影..."); } }
public class Person implements Runnable{ private CountDownLatch countDownLatch; public Person(CountDownLatch countDownLatch){ this.countDownLatch = countDownLatch; } @Override public void run() { try { Thread.sleep((long) (Math.random() * 0)); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(String.format("%s又有观众入场了", Thread.currentThread().getId())); countDownLatch.countDown(); System.out.println(String.format("%s还有%s人未入场", Thread.currentThread().getId(), countDownLatch.getCount())); } }
执行下看结果:
电影院等待人入场... 13又有观众入场了 11又有观众入场了 12又有观众入场了 11还有3人未入场 13还有4人未入场 12还有2人未入场 13又有观众入场了 11又有观众入场了 13还有1人未入场 人已到齐,开始播放电影... 11还有0人未入场
这个时候可以思考一下现实情况,不是任何时候电影院都是满场才放电影的,那么就需要设置一个时间,如果到时间了人还未到齐,就开始播放电影,这个程序怎么写呢。
public class Cinema { public static void main(String[] args) { CountDownLatch countDownLatch = new CountDownLatch(10); ExecutorService executor = Executors.newFixedThreadPool(3); for(int i=0; i<5; i++){ executor.execute(new Person(countDownLatch)); } System.out.println("电影院等待人入场..."); //阻塞当前线程,直到计数器的值为0 try { countDownLatch.await(300, TimeUnit.MILLISECONDS); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("人已到齐,开始播放电影..."); } }
这里用了CountDownLatch的await的另外一个重载方法,并且增加了CountDownLatch的阈值,让人更多一些方便跑数据。看结果:
电影院等待人入场... 12又有观众入场了 13又有观众入场了 13还有8人未入场 12还有9人未入场 11又有观众入场了 11还有7人未入场 12又有观众入场了 12还有6人未入场 13又有观众入场了 13还有5人未入场 人已到齐,开始播放电影...
发现还有5人未到场的时候,电影就开始播放了,是不是很赞。现在大家是不是对CountDownLatch的使用得心应手了,在这里需要提醒的是多线程环境下一定要注意异常,如果发生了异常该如何保证数据一致性,主线程是否要做回滚处理。我们在利用多线程实现性能提升的时候,必然会有线程安全的问题。