这篇文章主要介绍“如何使用CountDownLatch”,在日常操作中,相信很多人在如何使用CountDownLatch问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何使用CountDownLatch”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
想象一下这样一个场景,当我们需要等待某些线程执行完之后,再执行主线程的代码,要怎么实现?
可能有人会说,简单,用 join() 方法等待线程执行完成之后再执行主线程就行了,实现代码是这样的:
// 创建线程1 Thread t1 = new Thread(new Runnable() { @Override public void run() { // do something } }); t1.start(); // 创建线程2 Thread t2 = new Thread(new Runnable() { @Override public void run() { // do something } }); t2.start(); // 等待线程 1和线程 2 执行完 t1.join(); t2.join();
当然,如果使用的是 Thread 来执行任务,那这种写法也是可行的。然而真实的(编码)环境中我们是不会使用 Thread 来执行多任务的,而是会使用线程池来执行多任务,这样可以避免线程重复启动和销毁所带来的性能开销,实现代码如下:
// 创建固定线程数的线程池 ExecutorService executorService = Executors.newFixedThreadPool(2); // 任务一 executorService.submit(new Runnable() { @Override public void run() { // do something } }); // 任务二 executorService.submit(new Runnable() { @Override public void run() { // do something } });
那么这时候问题来了,线程池是没有 join() 方法的,那要怎么实现等待呢?
这个时候就要派出我方大将“CountDownLatch”啦。
吾有上将潘凤,可斩华雄... 出场数秒,潘凤...“卒”。
等等导演,我觉得剧情应该是这样的...
为了实现等待所有线程池执行完之后再执行主线程的逻辑,我决定使用 AQS(AbstractQueuedSynchronizer,抽象同步框架)下的著名类 CountDownLatch 来实现此功能,具体的实现代码如下:
public static void main(String[] args) throws InterruptedException { // 创建 CountDownLatch CountDownLatch countDownLatch = new CountDownLatch(2); // 创建固定线程数的线程池 ExecutorService executorService = Executors.newFixedThreadPool(2); // 任务一 executorService.submit(new Runnable() { @Override public void run() { // do something try { // 让此任务执行 1.2s Thread.sleep(1200); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("我是任务一"); countDownLatch.countDown(); } }); // 任务二 executorService.submit(new Runnable() { @Override public void run() { // do something try { // 让此任务执行 1.2s Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("我是任务二"); countDownLatch.countDown(); } }); // 等待任务执行完成 countDownLatch.await(); System.out.println("程序执行完成~"); }
以上程序执行结果如下:
从上述结果可以看出,主线程的执行是等待任务一和任务二都执行完成之后才执行的。
CountDownLatch 中 count down 是倒数的意思,latch 则是门闩的含义。整体含义可以理解为倒数的门栓,似乎有点“321,芝麻开门”的感觉,CountDownLatch 的作用也正是如此。
CountDownLatch 在创建的时候需要传入一个整数,在这个整数“倒数”到 0 之前,主线程需要一直挂起等待,直到其他的线程都执行之后,主线才能继续执行。
CountDownLatch 的实现是在其内部创建并维护了一个 volatile 类型的整数计数器,当调用 countDown() 方法时,会尝试将整数计数器 -1,当调用 wait() 方法时,当前线程就会判断整数计数器是否为 0,如果为 0,则继续往下执行,如果不为 0,则使当前线程进入等待状态,直到某个线程将计数器设置为 0,才会唤醒在 await() 方法中等待的线程继续执行。
// 线程被挂起直到 count 值为 0 才继续执行 public void await() throws InterruptedException { }; // 和 await() 类似,只不过等待一定的时间后 count 值还没变为 0 的话就会继续执行 public boolean await(long timeout, TimeUnit unit) throws InterruptedException { }; // 将 count 值减 1 public void countDown() { };
到此,关于“如何使用CountDownLatch”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。