`
qqjavagood
  • 浏览: 95344 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
文章分类
社区版块
存档分类
最新评论

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

    博客分类:
  • java
阅读更多
   
   数据量很大百万条记录,因此考虑到要用多线程并发执行,在写的过程中又遇到问题,我想统计所有子进程执行完毕总共的耗时,在第一个子进程创建前记录当前时间用system.currenttimemillis()在最后一个子进程结束后记录当前时间,两次一减得到的时间差即为总共的用时,代码如下     java代码  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");       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是否为空就知道还有没有子线程没有执行完了,类代码如下:     java代码  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是否为空就能知道是否还有线程未执行完   }   }       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是否为空就能知道是否还有线程未执行完    }    }        主线程中代码:     java代码  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");       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类     java代码  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;   }   }       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类     java代码  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() + " 个线程");//打印结束标记   }   }       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() + " 个线程");//打印结束标记    }    }        主线程中     java代码  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() + "结束.");//打印结束标记       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类     java代码  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() + " 个线程");   }   }       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() + " 个线程");    }    }        主线程中     java代码  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() + "结束.");//打印结束标记       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结束. 
  
 
1
4
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics