本程序的数据有可能是如下:

main thread work start

sub thread start working.

main thread work done.

now waiting sub thread done.

sub thread stop working.

now all done.

忽略标号, 当然输出也有可能是1和2调换位置了. 这个我们是无法控制的. 我们看下线程的join操作, 究竟干了什么.

这里是调用了

public final synchronized void join(long millis)

方法, 参数为0, 表示没有超时时间, 等到线程结束为止. join(millis)方法里面有这么一段代码:

说明, 当线程处于活跃状态的时候, 会一直等待, 直到这里的isAlive方法返回false, 才会结束.isAlive方法是一个本地方法, 他的作用是判断线程是否已经执行结束. 注释是这么写的:

Tests if this thread is alive. A thread is alive if it has been started and has not yet died.

可见, join系列方法可以帮助我们等待一个子线程的结束.

那么要问, 有没有另外一种方法可以等待子线程结束? 当然有的, 我们可以使用并发包下面的Future模式.

Future是一个任务执行的结果, 他是一个将来时, 即一个任务执行, 立即异步返回一个Future对象, 等到任务结束的时候, 会把值返回给这个future对象里面. 我们可以使用ExecutorService接口来提交一个线程.

这里, ThreadPoolExecutor 是实现了 ExecutorService的方法, sumbit的过程就是把一个Runnable接口对象包装成一个 Callable接口对象, 然后放到 workQueue里等待调度执行. 当然, 执行的启动也是调用了thread的start来做到的, 只不过这里被包装掉了. 另外, 这里的thread是会被重复利用的, 所以这里要退出主线程, 需要执行以下shutdown方法以示退出使用线程池. 扯远了.

这种方法是得益于Callable接口和Future模式, 调用future接口的get方法, 会同步等待该future执行结束, 然后获取到结果. Callbale接口的接口方法是 V call(); 是可以有返回结果的, 而Runnable的 void run(), 是没有返回结果的. 所以, 这里即使被包装成Callbale接口, future.get返回的结果也是null的.如果需要得到返回结果, 建议使用Callable接口.

通过队列来控制线程的进度, 是很好的一个理念. 我们完全可以自己搞个队列, 自己控制. 这样也可以实现. 不信看代码:

这里是得益于我们用了一个阻塞队列, 他的put操作和take操作都会阻塞(同步), 在满足条件的情况下.当我们调用take()方法时, 由于子线程还没结束, 队列是空的, 所以这里的take操作会阻塞, 直到子线程结束的时候, 往队列里面put了个元素, 表明自己结束了. 这时候主线程的take()就会返回他拿到的数据. 当然, 他拿到什么我们是不必去关心的.

以上几种情况都是针对子线程只有1个的时候. 当子线程有多个的时候, 情况就不妙了.

第一种方法, 你要调用很多个线程的join, 特别是当你的线程不是for循环创建的, 而是一个一个创建的时候.

第二种方法, 要调用很多的future的get方法, 同第一种方法.

第三种方法, 比较方便一些, 只需要每个线程都在queue里面 put一个元素就好了.但是, 第三种方法, 这个队列里的对象, 对我们是毫无用处, 我们为了使用队列, 而要不明不白浪费一些内存, 那有没有更好的办法呢?

有的, concurrency包里面提供了好多有用的东东, 其中, CountDownLanch就是我们要用的.

CountDownLanch 是一个倒数计数器, 给一个初始值(>=0), 然后每countDown一次就会减1, 这很符合等待多个子线程结束的场景: 一个线程结束的时候, countDown一次, 直到所有都countDown了 , 那么所有子线程就都结束了.

先看看CountDownLanch有哪些方法:

await: 会阻塞等待计数器减少到0位置. 带参数的await是多了等待时间.

countDown: 将当前的技术减1

getCount(): 返回当前的计数

显而易见, 我们只需要在子线程执行之前, 赋予初始化countDownLanch, 并赋予线程数量为初始值.

每个线程执行完毕的时候, 就countDown一下.主线程只需要调用await方法, 可以等待所有子线程执行结束, 看代码:

此种方法也适用于使用 ExecutorService summit 的任务的执行.

另外还有一个并发包的类CyclicBarrier, 这个是(子)线程之间的互相等待的利器. 栅栏, 就是把大家都在一个地方堵住, 就像水闸, 等大家都完成了之前的操作, 在一起继续下面的操作. 不过就不再本篇的讨论范围内了.

EOF

java 线程执行结束_Java_如何等待子线程执行结束相关推荐

  1. Java多线程之----主线程会等待子线程结束再结束么,怎么让主线程等待子线程结束呐?

    首先给出结论: 主线程和子线程之间没有谁先谁后结束这种关联,它们只是各自负责自己的线程任务,如果该线程的任务结束了,该线程自然会结束运行. talk is cheap,show me the code ...

  2. 【Java并发编程】主线程等待子线程的多种方法

    文章目录 1.Thread sleep() 2.Thread join() 3.synchronized 等待唤醒机制 4.ExecutorService isTerminated() + while ...

  3. Java多线程协作CountDownLatch,主线程等待子线程结束

    CountDownLatch,一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待. 主要方法 public CountDownLatch(int count);构造方 ...

  4. Java如何等待子线程执行结束

    参考:http://www.jiacheo.org/blog/262 工作中往往会遇到异步去执行某段逻辑, 然后先处理其他事情, 处理完后再把那段逻辑的处理结果进行汇总的产景, 这时候就需要使用线程了 ...

  5. 【多线程】学习记录七种主线程等待子线程结束之后在执行的方法

    最近遇到一个问题需要主线程等待所有的子线程结束,才能开始执行,统计所有的子线程执行结果,返回,网上翻阅各种资料,最后记录一下,找到七种方案 第一种:while循环 对于"等待所有的子线程结束 ...

  6. 如何实现java主线程等待子线程执行完毕之后再执行?

    本文转自:问题:如何实现java主线程等待子线程执行完毕之后再执行? - jseven - 博客园 点击关注强哥,查看更多精彩文章呀 工作总往往会遇到异步去执行某段逻辑, 然后先处理其他事情, 处理完 ...

  7. 日积月累:Java等待子线程执行完毕,再执行后续逻辑

    在实际开发过过程中,我们会经常遇见将一个"庞大"的任务拆分成多个子任务,各个子任务在独立的子线程中运行.待所有子线程的任务完成之后,在运行后续的业务,或者退出Main线程.代码如下 ...

  8. Java主线程等待子线程、线程池

    public class TestThread extends Thread { public void run() { System.out.println(this.getName() + &qu ...

  9. java等待5秒_Java并发编程-主线程等待子线程解决方案

    主线程等待所有子线程执行完成之后,再继续往下执行的解决方案 public class TestThread extends Thread { public void run() { System.ou ...

最新文章

  1. fiddler和wireshark工具介绍及对比 - [测试技术知识]
  2. (转)C/C++ Linux 程序员必须了解的 10 个工具
  3. python填充空值_python空值_python空值填充_python空值变量 - 云+社区 - 腾讯云
  4. .Net Core with 微服务 - 架构图
  5. D. Bananas in a Microwave
  6. 【渝粤题库】陕西师范大学100101美学概论作业(高起本)
  7. float数据在计算机内存中的存储方法
  8. FFmpeg wav转pcm(十一)
  9. 移动端学习笔记(小强测试品牌学员作品)
  10. scala连接mongodb_MongoDB 的用户配置与基于Scala的使用
  11. php utf8 gbk 数组 互转
  12. Linux-Monitor-Tools
  13. Manjaro安装Nvidia显卡驱动失败或者启动黑屏卡死的原因以及Nvidia Prime与Intel核显切换方法
  14. 谈一谈PAC学习理论
  15. centos7 更新 Firefox 版本
  16. 运行时错误‘53’:文件未找到:MathPage.WLL
  17. Linux编辑器-gcc/g++使用
  18. IDEA 配置Go环境,编写Golang代码,学习笔记(一)
  19. twrp双清勾选哪两个_免费读书app,我只留了这两个。
  20. 奥维奥:新零售下,家具家居该如何乘风破浪?

热门文章

  1. java socket 重连复用_Java Socket编程基础及深入讲解(示例代码)
  2. 在java中字符流怎么复制_Java 使用字符流拷贝数据
  3. linux重启memcache_Linux下的Memcache安装方法
  4. oracle中exp/imp讲解
  5. 计算机分数的简便运算,分数的简便运算和分数的解方程
  6. python向空列表添加列表_Python列表核心知识点汇总
  7. 我的世界服务器显示英文,我的世界pixelmon服务器技能显示英文
  8. python验证码重叠_用Python机器学习搞定验证码
  9. a byte of python中文版_面试官问 Python 版 “垃圾回收”机制,我没答上来
  10. 【转】深度理解C# 的执行原理