Java多线程--让主线程等待所有子线程执行完毕在执行_java

朋友让我帮忙写个程序从文本文档中导入数据到oracle数据库中,技术上没有什么难度,文档的格式都是固定的只要对应数据库中的字段解析就行了,关键在于性能。

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

long tStart = System.currentTimeMillis();
System.out.println(Thread.currentThread().getName() + "开始");//打印开始标记
for (int ii = 0; ii < threadNum; ii++) {//开threadNum个线程
Runnable r = new Runnable(){
@Override
public void run(){
System.out.println(Thread.currentThread().getName() + "开始");
//做一些事情... ...
System.out.println(Thread.currentThread().getName() + "结束.");
}
}
Thread t = new Thread(r);
t.start();
}
System.out.println(Thread.currentThread().getName() + "结束.");//打印结束标记
long tEnd = System.currentTimeMillis();
System.out.println("总共用时:"+ (tEnd - tStart) + "millions");

结果是几乎在for循环结束的瞬间就执行了主线程打印总共用时的语句,原因是所有的子线程是并发执行的,它们运行时主线程也在运行,这就引出了一个问题即本文标题如何"让主线程等待所有子线程执行完毕"。试过在每个子线程开始后加上t.join(),结果是所有线程都顺序执行,这就失去了并发的意义了,显然不是我想要的。 

网上Google了很久也没有找到解决方案,难道就没有人遇到过这种需求吗?还是这个问题太简单了?无耐只得自己想办法了... 

最后我的解决办法是,自定义一个ImportThread类继承自java.lang.Thread,重载run()方法,用一个List属性保存所有产生的线程,这样只要判断这个List是否为空就知道还有没有子线程没有执行完了,类代码如下: 

public class ImportThread extends Thread {
private static List<Thread> runningThreads = new ArrayList<Thread>();
public ImportThread() {
}
@Override
public void run() {
regist(this);//线程开始时注册
System.out.println(Thread.currentThread().getName() + "开始...");//打印开始标记
//做一些事情... ...
unRegist(this);//线程结束时取消注册
System.out.println(Thread.currentThread().getName() + "结束.");//打印结束标记
}
public void regist(Thread t){
  synchronized(runningThreads){
    runningThreads.add(t);
  }
}
public void unRegist(Thread t){
  synchronized(runningThreads){
    runningThreads.remove(t);
  }
}
public static boolean hasThreadRunning() {
return (runningThreads.size() > 0);//通过判断runningThreads是否为空就能知道是否还有线程未执行完
}
}

主线程中代码: 

long tStart = System.currentTimeMillis();
System.out.println(Thread.currentThread().getName() + "开始");//打印开始标记
for (int ii = 0; ii < threadNum; ii++) {//开threadNum个线程
Thread t = new ImportThread();
t.start();
}
while(true){//等待所有子线程执行完
if(!ImportThread.hasThreadRunning()){
break;
}
Thread.sleep(500);
}
System.out.println(Thread.currentThread().getName() + "结束.");//打印结束标记
long tEnd = System.currentTimeMillis();
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类 
 

  public class MyCountDown {
private int count;
public MyCountDown(int count){
this.count = count;
}
public synchronized void countDown(){
count--;
}
public synchronized boolean hasNext(){
return (count > 0);
}
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
}
}

ImportThread类 

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

主线程中 

System.out.println(Thread.currentThread().getName() + "开始");//打印开始标记
MyCountDown c = new MyCountDown(threadNum);//初始化countDown
for (int ii = 0; ii < threadNum; ii++) {//开threadNum个线程
Thread t = new ImportThread(c);
t.start();
}
while(true){//等待所有子线程执行完
if(!c.hasNext()) break;
}
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类 

public class ImportThread extends Thread {
private CountDownLatch threadsSignal;
public ImportThread(CountDownLatch threadsSignal) {
this.threadsSignal = threadsSignal;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "开始...");
//Do somethings
threadsSignal.countDown();//线程结束时计数器减1
System.out.println(Thread.currentThread().getName() + "结束. 还有" + threadsSignal.getCount() + " 个线程");
}
}

主线程中 

CountDownLatch threadSignal = new CountDownLatch(threadNum);//初始化countDown
for (int ii = 0; ii < threadNum; ii++) {//开threadNum个线程
final Iterator<String> itt = it.get(ii);
Thread t = new ImportThread(itt,sql,threadSignal);
t.start();
}
threadSignal.await();//等待所有子线程执行完
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
, 多线程
, java
, 执行完毕
, 等待结束
java多线程等待
java 多线程 执行完毕、java等待线程执行完毕、等待线程执行完毕、c 等待线程执行完毕、等待所有线程执行完毕,以便于您获取更多的相关知识。

时间: 2024-09-20 20:38:27

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

Java多线程--让主线程等待所有子线程执行完毕代码

采用CountDownLatch类来实现     主线程    package test; import java.util.concurrent.CountDownLatch; public class Main {  /**   *   * @author Administrator/2012-3-1/上午09:36:55   */  public static void main(String[] args) {   int threadNum = 10;   CountDownLatch

多线程同步-主线程等待所有子线程完成案例

http://blog.csdn.net/qiujuer/article/details/34862469 有时候我们会遇到这样的问题:做一个大的事情可以被分解为做一系列相似的小的事情,而小的事情无非就是参数上有可能不相同而已! 此时,如果不使用线程,我们势必会浪费非常多的时间来完成整个大的事情,而使用线程的话将会存在这样的问题: 主线程启动所有子线程并发执行后主线程就直接返回了,导致外部函数判读整个大的事情完成了,但是实际上并没有完成! 针对以上情况我想我会采用多线程方式执行同时解决主线程等待

JAVA进阶----主线程等待子线程各种方案比较(转)

创建线程以及管理线程池基本理解 参考原文链接:http://www.oschina.net/question/12_11255?sort=time  一.创建一个简单的java线程 在 Java 语言中,一个最简单的线程如下代码所示:  Java代码   Runnable runnable = new Runnable(){      public void run(){         System.out.println("Run");      }   }   可通过下面一行代码

当主线程崩溃而其它线程继续运行时发生什么

孤线程模式 症状 治疗和预防措施 总结 参考资料 关于作者 对本文的评价 当主线程崩溃而其它线程继续运行时发生什么? Eric E. Allen(eallen@cs.rice.edu) 博士研究生候选人,Rice 大学 2001 年 8 月 在多线程代码中,使用驱动其它线程所负责的动作的单个主线程是常见的.这个主线程发送消息,通常是通过把它们放到一个队列中,然后其它线程处理这些消息.但是如果主线程抛出一个异常,那么剩余的线程会继续运行,等待更多输入到该队列,导致程序冻结.在诊断 Java 代码的

linux多线程编程中如何等待过个线程退出

问题描述 linux多线程编程中如何等待过个线程退出 linux多线程编程中,如果线程A创建了线程B,我知道用pthread__ join可以令线程A 阻塞然后等待线程B的退出.如果线程A创建了三个线程B,C,D,执行完的先后顺序不知.想让A必须等待三个线程都退出后再退出,应该怎么做? 连用pthread__join三次吗???但是第一次用了pthread__join后,A不就阻塞了吗? 解决方案 多线程编程(一):线程创建和退出Linux多线程编程(创建线程)Linux多线程编程(创建线程)

android-Android线程间同步问题,实现主线程死等新线程处理结束

问题描述 Android线程间同步问题,实现主线程死等新线程处理结束 我的主线程是activity,在主线程里开启了线程R1,希望R1的任务处理完成后通知主线程继续,否则主线程一直等待,怎么实现? 解决方案 首先你这样的需求是违背android官方设计的,你应该考虑一下要实现你的功能,换一种需求(实现方式)是否可以. 主线程负责呈现画面增强交互,不应该阻塞,非要实现这样的功能, 可以在主线程是activity开启线程R1,然后什么事儿也不做,当R1的任务处理完成后通知主线程继续后再做事儿(绘制画

java 多线程,这种情况是否正常。线程总数一直在上升,但是内存没有出现过大的波动

问题描述 java 多线程,这种情况是否正常.线程总数一直在上升,但是内存没有出现过大的波动 因根据不同的任务需要定时创建线程池,为什么线程总数一直在上升? 解决方案 线程数一直上升,建议开通jmx,利用远程的工具查看,例如jdk自带的jvisualvm.出现这种情况原因比较多,例如:1)线程之间资源竞争,导致前面线程池没有释放资源,后面线程阻塞2)线程出现死循环3)优先级线程一直占据竞争资源4)某些方法同步锁或者某些变量同步锁 建议用jvisualvm查看应该关闭的线程堵塞的方法的行数. 解决

socket-C#主线程如何访问子线程 局域网通讯

问题描述 C#主线程如何访问子线程 局域网通讯 我创建了一个子线程用来进行socket连接 我发送消息用文本框 下面问题来了 文本框的知如何传给子线程的socket发送部分啊 或是我这种写法就不对在创建别的线程啊 解决方案 按Win32思路1.全局数据区 int m_datalen=0; TCHAR m_datalen[MAX_PATH]; HANDLE m_hMutex; HANDLE m_hEvent[2];2.建立全局数据共享锁 m_hMutex = CreateMutex(NULL FA

linux 把主线程cancel 掉后,由主线程创建的子线程会不会被cancel掉?

问题描述 linux 把主线程cancel 掉后,由主线程创建的子线程会不会被cancel掉? linux 把主线程cancel 掉后,由主线程创建的子线程会不会被cancel掉? 解决方案 不会.进程是独立的,不是线程.