数据量很大百万条记录,因此考虑到要用多线程并发执行,在写的过程中又遇到问题,我想统计所有子进程执行完毕总共的耗时,在第一个子进程创建前记录当前时间用System.currentTimeMillis()在最后一个子进程结束后记录当前时间,两次一减得到的时间差即为总共的用时,代码如下

  1. long tStart = System.currentTimeMillis();
  2. System.out.println(Thread.currentThread().getName() + "开始");//打印开始标记
  3. for (int ii = 0; ii < threadNum; ii++) {//开threadNum个线程
  4. Runnable r = new Runnable(){
  5. @Override
  6. public void run(){
  7. System.out.println(Thread.currentThread().getName() + "开始");
  8. //做一些事情... ...
  9. System.out.println(Thread.currentThread().getName() + "结束.");
  10. }
  11. }
  12. Thread t = new Thread(r);
  13. t.start();
  14. }
  15. System.out.println(Thread.currentThread().getName() + "结束.");//打印结束标记
  16. long tEnd = System.currentTimeMillis();
  17. System.out.println("总共用时:"+ (tEnd - tStart) + "millions");

结果是几乎在for循环结束的瞬间就执行了主线程打印总共用时的语句,原因是所有的子线程是并发执行的,它们运行时主线程也在运行,这就引出了一个问题即本文标题如何"让主线程等待所有子线程执行完毕"。试过在每个子线程开始后加上t.join(),结果是所有线程都顺序执行,这就失去了并发的意义了,显然不是我想要的。 
    网上Google了很久也没有找到解决方案,难道就没有人遇到过这种需求吗?还是这个问题太简单了?无耐只得自己想办法了... 
    最后我的解决办法是,自定义一个ImportThread类继承自java.lang.Thread,重载run()方法,用一个List属性保存所有产生的线程,这样只要判断这个List是否为空就知道还有没有子线程没有执行完了,类代码如下:

  1. public class ImportThread extends Thread {
  2. private static List<Thread> runningThreads = new ArrayList<Thread>();
  3. public ImportThread() {
  4. }
  5. @Override
  6. public void run() {
  7. regist(this);//线程开始时注册
  8. System.out.println(Thread.currentThread().getName() + "开始...");//打印开始标记
  9. //做一些事情... ...
  10. unRegist(this);//线程结束时取消注册
  11. System.out.println(Thread.currentThread().getName() + "结束.");//打印结束标记
  12. }
  13. public void regist(Thread t){
  14. synchronized(runningThreads){
  15. runningThreads.add(t);
  16. }
  17. }
  18. public void unRegist(Thread t){
  19. synchronized(runningThreads){
  20. runningThreads.remove(t);
  21. }
  22. }
  23. public static boolean hasThreadRunning() {
  24. return (runningThreads.size() > 0);//通过判断runningThreads是否为空就能知道是否还有线程未执行完
  25. }
  26. }

主线程中代码:

  1. long tStart = System.currentTimeMillis();
  2. System.out.println(Thread.currentThread().getName() + "开始");//打印开始标记
  3. for (int ii = 0; ii < threadNum; ii++) {//开threadNum个线程
  4. Thread t = new ImportThread();
  5. t.start();
  6. }
  7. while(true){//等待所有子线程执行完
  8. if(!ImportThread.hasThreadRunning()){
  9. break;
  10. }
  11. Thread.sleep(500);
  12. }
  13. System.out.println(Thread.currentThread().getName() + "结束.");//打印结束标记
  14. long tEnd = System.currentTimeMillis();
  15. System.out.println("总共用时:"+ (tEnd - tStart) + "millions");

打印的结果是: 
            main开始 
            Thread-1开始... 
            Thread-5开始... 
            Thread-0开始... 
            Thread-2开始... 
            Thread-3开始... 
            Thread-4开始... 
            Thread-5结束. 
            Thread-4结束. 
            Thread-2结束. 
            Thread-0结束. 
            Thread-3结束. 
            Thread-1结束. 
            main结束. 
            总共用时:20860millions 
    可以看到main线程是等所有子线程全部执行完后才开始执行的。 
    ==================================================以下为第二次编辑=============================================== 
    上面的方法有一个隐患:如果线程1开始并且结束了,而其他线程还没有开始此时runningThreads的size也为0,主线程会以为所有线程都执行完了。解决办法是用一个非简单类型的计数器来取代List型的runningThreads,并且在线程创建之前就应该设定好计数器的值。 
    MyCountDown类

  1. public class MyCountDown {
  2. private int count;
  3. public MyCountDown(int count){
  4. this.count = count;
  5. }
  6. public synchronized void countDown(){
  7. count--;
  8. }
  9. public synchronized boolean hasNext(){
  10. return (count > 0);
  11. }
  12. public int getCount() {
  13. return count;
  14. }
  15. public void setCount(int count) {
  16. this.count = count;
  17. }
  18. }

ImportThread类

  1. public class ImportThread extends Thread {
  2. private MyCountDown c;
  3. public ImportThread(MyCountDown c) {
  4. this.c = c;
  5. }
  6. @Override
  7. public void run() {
  8. System.out.println(Thread.currentThread().getName() + "开始...");//打印开始标记
  9. //Do something
  10. c.countDown();//计时器减1
  11. System.out.println(Thread.currentThread().getName() + "结束. 还有" + c.getCount() + " 个线程");//打印结束标记
  12. }
  13. }

主线程中

  1. System.out.println(Thread.currentThread().getName() + "开始");//打印开始标记
  2. MyCountDown c = new MyCountDown(threadNum);//初始化countDown
  3. for (int ii = 0; ii < threadNum; ii++) {//开threadNum个线程
  4. Thread t = new ImportThread(c);
  5. t.start();
  6. }
  7. while(true){//等待所有子线程执行完
  8. if(!c.hasNext()) break;
  9. }
  10. System.out.println(Thread.currentThread().getName() + "结束.");//打印结束标记

打印结果: 
            main开始 
            Thread-2开始... 
            Thread-1开始... 
            Thread-0开始... 
            Thread-3开始... 
            Thread-5开始... 
            Thread-4开始... 
            Thread-5结束. 还有5 个线程 
            Thread-1结束. 还有4 个线程 
            Thread-4结束. 还有3 个线程 
            Thread-2结束. 还有2 个线程 
            Thread-3结束. 还有1 个线程 
            Thread-0结束. 还有0 个线程 
            main结束. 
    更简单的方法:使用java.util.concurrent.CountDownLatch代替MyCountDown,用await()方法代替while(true){...}
    ImportThread类

  1. public class ImportThread extends Thread {
  2. private CountDownLatch threadsSignal;
  3. public ImportThread(CountDownLatch threadsSignal) {
  4. this.threadsSignal = threadsSignal;
  5. }
  6. @Override
  7. public void run() {
  8. System.out.println(Thread.currentThread().getName() + "开始...");
  9. //Do somethings
  10. threadsSignal.countDown();//线程结束时计数器减1
  11. System.out.println(Thread.currentThread().getName() + "结束. 还有" + threadsSignal.getCount() + " 个线程");
  12. }
  13. }

主线程中

  1. CountDownLatch threadSignal = new CountDownLatch(threadNum);//初始化countDown
  2. for (int ii = 0; ii < threadNum; ii++) {//开threadNum个线程
  3. final Iterator<String> itt = it.get(ii);
  4. Thread t = new ImportThread(itt,sql,threadSignal);
  5. t.start();
  6. }
  7. threadSignal.await();//等待所有子线程执行完
  8. System.out.println(Thread.currentThread().getName() + "结束.");//打印结束标记

打印结果: 
            main开始 
            Thread-1开始... 
            Thread-0开始... 
            Thread-2开始... 
            Thread-3开始... 
            Thread-4开始... 
            Thread-5开始... 
            Thread-0结束. 还有5 个线程 
            Thread-1结束. 还有4 个线程 
            Thread-4结束. 还有3 个线程 
            Thread-2结束. 还有2 个线程 
            Thread-5结束. 还有1 个线程 
            Thread-3结束. 还有0 个线程 
            main结束.

Java多线程--让主线程等待所有子线程执行完毕的更多相关文章

  1. java主线程等待所有子线程执行完毕在执行(常见面试题)

    java主线程等待所有子线程执行完毕在执行(常见面试题) java主线程等待所有子线程执行完毕在执行,这个需求其实我们在工作中经常会用到,比如用户下单一个产品,后台会做一系列的处理,为了提高效率,每个 ...

  2. Java主线程等待所有子线程执行完毕再执行解决办法(转)

    方法一: Thread.join()方法,亲测可行,thread.join()方法 Vector<Thread> ts = new Vector<Thread>(); for  ...

  3. c#等待所有子线程执行完毕方法

    当我们在使用线程中,你会发现主线结束后子线程的结果才显示出来.现在我要等待所以子线程结束,然后在显示结果,怎么做呢? 方法如下: 1.使用 ManualResetEvent,代码如下:  using  ...

  4. Java多线程--让主线程等待子线程执行完毕

    使用Java多线程编程时经常遇到主线程需要等待子线程执行完成以后才能继续执行,那么接下来介绍一种简单的方式使主线程等待. java.util.concurrent.CountDownLatch 使用c ...

  5. [Java][Android] 多线程同步-主线程等待全部子线程完毕案例

    有时候我们会遇到这种问题:做一个大的事情能够被分解为做一系列相似的小的事情,而小的事情无非就是參数上有可能不同样而已! 此时,假设不使用线程,我们势必会浪费许多的时间来完毕整个大的事情.而使用线程的话 ...

  6. java多线程实现主线程等待子线程执行完问题

    本文介绍两种主线程等待子线程的实现方式,以5个子线程来说明: 1.使用Thread的join()方法,join()方法会阻塞主线程继续向下执行. 2.使用Java.util.concurrent中的C ...

  7. Java父线程(或是主线程)等待所有子线程退出

    static void testLock1(){ final AtomicInteger waitCount = new AtomicInteger(30000); final Object wait ...

  8. netframework中等待多个子线程执行完毕并计算执行时间

    本文主要描述在.netframework中(实验环境.netframework版本为4.6.1)提供两种方式等待多个子线程执行完毕. ManualResetEvent 在多线程中,将ManualRes ...

  9. Java并发编程原理与实战六:主线程等待子线程解决方案

    本文将研究的是主线程等待所有子线程执行完成之后再继续往下执行的解决方案 public class TestThread extends Thread { public void run() { Sys ...

随机推荐

  1. 论移动端Hybid开发

    以下内容code地址:https://github.com/wytings/Hybrid 背景:公司业务的发展和开发需求升级,我们需要Hybrid了.市面上有很多开源的Hybrid框架给我们直接使用, ...

  2. C语言之原码、反码和补码

    原码.反码和补码 1).数据在内存中存储的时候都是以二进制的形式存储的. int num = 10; 原码.反码.补码都是二进制.只不过是二进制的不同的表现形式. 数据是以补码的二进制存储的. 2). ...

  3. 安装windows后grub的恢复

    问题: 原本是:双系统(linux和windows),后来换windows版本覆盖了grub2 解决方法: 进入windows后下载并安装EasyBCD并添加grub2的选项,重启看见了熟悉的启动项, ...

  4. CODEFORCES-PROBLEMSET

    1A 水题   然而看不仔细爆int了 c++ #include <bits/stdc++.h> using namespace std; typedef long long ll; in ...

  5. 供求WAP-VUE 笔记

    记录项目的经历 1. 项目简介 1. 项目采用 vue.js 显示数据的 wap 页面, v-resourse 异步请求, v-router 路由(暂时没用) 2. 采用 flex 布局页面 2. 页 ...

  6. C#动态创建两个按钮,btn2复制btn1的Click事件,匿名委托

    现在有一个按钮btn1,要动态创建出一个btn2,需要btn2点击时调用btn1的点击. 在delphi中这种操作很简单:btn2.onClick:=btn1.onClick,因为onClick就是个 ...

  7. Girl Develop It Chapter Leaders at 2015 Annual Leadership Summit

    Girl Develop It Chapter Leaders at 2015 Annual Leadership Summit Corinne Warnshuis, Executive Direct ...

  8. centos7 install rvm

    不管其他,先按要求更新一下包 yum install -y gcc-c++ patch readline readline-devel zlib zlib-devel libyaml-devel li ...

  9. CODE[VS]-寻找子串位置-字符串处理-天梯青铜

    题目描述 Description 给出字符串a和字符串b,保证b是a的一个子串,请你输出b在a中第一次出现的位置. 输入描述 Input Description 仅一行包含两个字符串a和b 输出描述 ...

  10. shrio配置说明

    1.引入Shiro的Maven依赖 <!-- Spring 整合Shiro需要的依赖 --> <dependency> <groupId>org.apache.sh ...