Java多線程--讓主線程等待所有子線程執行完畢

來源:互聯網
上載者:User

標籤:

 資料量很大百萬條記錄,因此考慮到要用多線程並發執行,在寫的過程中又遇到問題,我想統計所有子進程執行完畢總共的耗時,在第一個子進程建立前記錄目前時間用System.currentTimeMillis()在最後一個子進程結束後記錄目前時間,兩次一減得到的時間差即為總共的用時,代碼如下 
   

Java代碼  
  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是否為空白就知道還有沒有子線程沒有執行完了,類代碼如下: 
   

Java代碼  
  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. }  


    主線程中代碼: 
   

Java代碼  
  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類 
   

Java代碼  
  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代碼  
  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. }  


    主線程中 
   

Java代碼  
  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類 
   

Java代碼  
  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. }  


    主線程中 
   

Java代碼  
  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多線程--讓主線程等待所有子線程執行完畢

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.