首页 > 编程语言 >Java多线程--让主线程等待所有子线…

Java多线程--让主线程等待所有子线…

时间:2023-05-07 22:02:59浏览次数:54  
标签:... Java Thread -- ii 线程 结束 多线程 public


朋友让我帮忙写个程序从文本文档中导入数据到oracle数据库中,技术上没有什么难度,文档的格式都是固定的只要对应数据库中的字段解析就行了,关键在于性能。
      数据量很大百万条记录,因此考虑到要用多线程并发执行,在写的过程中又遇到问题,我想统计所有子进程执行完毕总共的耗时,在第一个子进程创建前记录当前时间用System.currentTimeMillis()在最后一个子进程结束后记录当前时间,两次一减得到的时间差即为总共的用时,代码如下
     

Java代码

Java多线程--让主线程等待所有子线…_子线程

 

Java多线程--让主线程等待所有子线…_Java_02

Java多线程--让主线程等待所有子线…_子线程_03

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




 

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

 

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

 

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


 

   

Java代码

Java多线程--让主线程等待所有子线…_子线程

 

Java多线程--让主线程等待所有子线…_Java_02

Java多线程--让主线程等待所有子线…_子线程_03


1. public class ImportThread extends Thread {   
2. private static List runningThreads = new ArrayList();   
3. public ImportThread() {   
4. }   
5. @Override  
6. public void run() {   
7. regist(this);//线程开始时注册   
8. + "开始...");//打印开始标记   
9. //做一些事情... ...   
10. unRegist(this);//线程结束时取消注册   
11. + "结束.");//打印结束标记   
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. }



 

    主线程中代码:

 

   

Java代码

Java多线程--让主线程等待所有子线…_子线程

 

Java多线程--让主线程等待所有子线…_Java_02

Java多线程--让主线程等待所有子线…_子线程_03


1. long tStart = System.currentTimeMillis();   
2. + "开始");//打印开始标记   
3. for (int ii = 0; ii < threadNum; ii++) {//开threadNum个线程   
4. t = new ImportThread();   
5. t.start();   
6. }   
7. while(true){//等待所有子线程执行完   
8. if(!ImportThread.hasThreadRunning()){   
9. break;   
10. }   
11. Thread.sleep(500);   
12. }   
13. + "结束.");//打印结束标记   
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类

 

   

Java代码

Java多线程--让主线程等待所有子线…_子线程

 

Java多线程--让主线程等待所有子线…_Java_02

Java多线程--让主线程等待所有子线…_子线程_03

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类

 

   

Java代码

Java多线程--让主线程等待所有子线…_子线程

 

Java多线程--让主线程等待所有子线…_Java_02

Java多线程--让主线程等待所有子线…_子线程_03


    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. + "开始...");//打印开始标记   
    9. //Do something   
    10. c.countDown();//计时器减1   
    11. + "结束. 还有" + c.getCount() + " 个线程");//打印结束标记   
    12. }   
    13. }




     

        主线程中

     

       

    Java代码

    Java多线程--让主线程等待所有子线…_子线程

     

    Java多线程--让主线程等待所有子线…_Java_02

    Java多线程--让主线程等待所有子线…_子线程_03



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




       

          打印结果:

       

                          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代码

      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() + " 个线程");
          }
          }



       

          主线程中

       

          Java代码


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




         

            打印结果:

         

                            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,Thread,--,ii,线程,结束,多线程,public
        From: https://blog.51cto.com/u_548275/6252617

        相关文章

        • Hibernate4之二级缓存配置
          缓存:缓存是什么,解决什么问题? 位于速度相差较大的两种硬件/软件之间的,用于协调两者数据传输速度差异的结构,均可称之为缓存Cache。缓存目的:让数据更接近于应用程序,协调速度不匹配,使访问速度更快。 缓存的范围分为3类: 1.事务范围(单Session即一级缓存)   事务范围......
        • Python程序与设计
          2-27在命令行窗口中启动的Python解释器中实现在Python自带的IDLE中实现print("Helloworld")编码规范每个import语句只导入一个模块,尽量避免一次导入多个模块不要在行尾添加分号“:”,也不要用分号将两条命令放在同一行建议每行不超过80个字符使用必要的空行可以增加代码的可读性运......
        • Python学习
          3-13字符串类型字符串类型:str   1.定义格式:       变量='内容'           打印一行       变量="内容"           打印一行       变量='''内容'''或者三引号           可以通过回车的方式换行,......
        • 冒泡排序
          voidbubble_sort(intarr[],intsz)//这里的arr[]传递的是首地址{ inti=0;for(i=0;i<sz-1;i++)//一共进行多少趟 {intj=0;for(j=0;j<sz-1-i;j++)//每一趟进行多少次冒泡排序 { if(arr[j]>arr[j+1])//如果判定条件成立将上一个数值赋值给下一个数值{ int......
        • Python学习
          3-13字符串类型字符串类型:str   1.定义格式:       变量='内容'           打印一行       变量="内容"           打印一行       变量='''内容'''或者三引号           可以通过回车的方式换行,......
        • 从来都没有理解浅拷贝与深拷贝?我非把你教会不可!最全的深拷贝方案,绝对全!!看这一篇就够了
          首先,想真正理解深浅拷贝,需要清楚地知道堆和栈,那么你知道简单数据类型和引用数据类型在堆和栈的关系吗?栈:基本数据类型的值,引用数据类型的地址。堆:引用数据类型的值。我画个图,便于你理解。堆空间远远大于栈空间,可以发现,当数据类型为简单数据类型时,它的值和地址都在堆中,所以一般对于深......
        • 《asyncio 系列》7. 在 asyncio 中引入多线程
          楔子在从头开始开发新的IO密集型应用程序时,asyncio可能是首选技术,并且也要使用与asyncio搭配工作的非阻塞库,如asyncpg、aiohttp等等。然而我们工作的很大一部分可能是使用阻塞IO库管理现有的代码,例如对HTTP发请求的requests,用于PostgreSQL数据库的psycopg2,或其他......
        • NET 6中的自托管Web API
          原文:NET6中的自托管WebAPI-我爱学习网(5axxw.com)我需要向现有库中添加一个非常简单的WebAPI,以便Python可以与应用程序通信。简单的请求/JSON响应。这比最初想象的更具挑战性。我习惯了NodeJ,在那里像Express这样的库只需几行代码就可以做到这一点。显然,web服务器需要集......
        • Python文本处理
           binascii—ConvertbetweenbinaryandASCII—Python3.11.3documentation Hackbright-challenges/hexconvert.pyatmaster·kritikadusad/Hackbright-challenges·GitHub hex2bin/hex2bin.pyatmain·jasonalexander-ja/hex2bin(github.com)importre......
        • 2.ansible常用的模块01
          1.模块?模块实际上就是脚本,是ansible调用的对象,主要是用来通过调用它去远程执行某些命令功能。2.常用的模块2.1shell模块ansible默认的模块是command,其中shell模块与command模块区别:1.command模块的命令不启动shell,直接通过ssh执行命令......