欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java多線程--讓主線程等待所有子線程執(zhí)行完畢在執(zhí)行

 更新時間:2016年11月09日 08:59:35   作者:yadsun  
Java主線程等待所有子線程執(zhí)行完畢在執(zhí)行,其實在我們的工作中經(jīng)常的用到,本篇文章就介紹了Java多線程--讓主線程等待所有子線程執(zhí)行完畢在執(zhí)行,有需要的可以了解一下。

朋友讓我?guī)兔憘€程序從文本文檔中導(dǎo)入數(shù)據(jù)到oracle數(shù)據(jù)庫中,技術(shù)上沒有什么難度,文檔的格式都是固定的只要對應(yīng)數(shù)據(jù)庫中的字段解析就行了,關(guān)鍵在于性能。

數(shù)據(jù)量很大百萬條記錄,因此考慮到要用多線程并發(fā)執(zhí)行,在寫的過程中又遇到問題,我想統(tǒng)計所有子進(jìn)程執(zhí)行完畢總共的耗時,在第一個子進(jìn)程創(chuàng)建前記錄當(dāng)前時間用System.currentTimeMillis()在最后一個子進(jìn)程結(jié)束后記錄當(dāng)前時間,兩次一減得到的時間差即為總共的用時,代碼如下 

long tStart = System.currentTimeMillis(); 
System.out.println(Thread.currentThread().getName() + "開始");//打印開始標(biāo)記 
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() + "結(jié)束."); 
} 
} 
Thread t = new Thread(r); 
t.start(); 
} 
System.out.println(Thread.currentThread().getName() + "結(jié)束.");//打印結(jié)束標(biāo)記 
long tEnd = System.currentTimeMillis(); 
System.out.println("總共用時:"+ (tEnd - tStart) + "millions"); 

結(jié)果是幾乎在for循環(huán)結(jié)束的瞬間就執(zhí)行了主線程打印總共用時的語句,原因是所有的子線程是并發(fā)執(zhí)行的,它們運行時主線程也在運行,這就引出了一個問題即本文標(biāo)題如何"讓主線程等待所有子線程執(zhí)行完畢"。試過在每個子線程開始后加上t.join(),結(jié)果是所有線程都順序執(zhí)行,這就失去了并發(fā)的意義了,顯然不是我想要的。 

網(wǎng)上Google了很久也沒有找到解決方案,難道就沒有人遇到過這種需求嗎?還是這個問題太簡單了?無耐只得自己想辦法了... 

最后我的解決辦法是,自定義一個ImportThread類繼承自java.lang.Thread,重載run()方法,用一個List屬性保存所有產(chǎn)生的線程,這樣只要判斷這個List是否為空就知道還有沒有子線程沒有執(zhí)行完了,類代碼如下: 

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() + "開始...");//打印開始標(biāo)記 
//做一些事情... ... 
unRegist(this);//線程結(jié)束時取消注冊 
System.out.println(Thread.currentThread().getName() + "結(jié)束.");//打印結(jié)束標(biāo)記 
} 
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是否為空就能知道是否還有線程未執(zhí)行完 
} 
} 

主線程中代碼: 

long tStart = System.currentTimeMillis(); 
System.out.println(Thread.currentThread().getName() + "開始");//打印開始標(biāo)記 
for (int ii = 0; ii < threadNum; ii++) {//開threadNum個線程 
Thread t = new ImportThread(); 
t.start(); 
} 
while(true){//等待所有子線程執(zhí)行完 
if(!ImportThread.hasThreadRunning()){ 
break; 
} 
Thread.sleep(500); 
} 
System.out.println(Thread.currentThread().getName() + "結(jié)束.");//打印結(jié)束標(biāo)記 
long tEnd = System.currentTimeMillis(); 
System.out.println("總共用時:"+ (tEnd - tStart) + "millions"); 

打印的結(jié)果是: 

main開始 
Thread-1開始... 
Thread-5開始... 
Thread-0開始... 
Thread-2開始... 
Thread-3開始... 
Thread-4開始... 
Thread-5結(jié)束. 
Thread-4結(jié)束. 
Thread-2結(jié)束. 
Thread-0結(jié)束. 
Thread-3結(jié)束. 
Thread-1結(jié)束. 
main結(jié)束.          

總共用時:20860millions 

可以看到main線程是等所有子線程全部執(zhí)行完后才開始執(zhí)行的。 

================================================================================================= 

上面的方法有一個隱患:如果線程1開始并且結(jié)束了,而其他線程還沒有開始此時runningThreads的size也為0,主線程會以為所有線程都執(zhí)行完了。解決辦法是用一個非簡單類型的計數(shù)器來取代List型的runningThreads,并且在線程創(chuàng)建之前就應(yīng)該設(shè)定好計數(shù)器的值。 

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() + "開始...");//打印開始標(biāo)記 
//Do something 
c.countDown();//計時器減1 
System.out.println(Thread.currentThread().getName() + "結(jié)束. 還有" + c.getCount() + " 個線程");//打印結(jié)束標(biāo)記 
} 
} 

主線程中 

System.out.println(Thread.currentThread().getName() + "開始");//打印開始標(biāo)記 
MyCountDown c = new MyCountDown(threadNum);//初始化countDown 
for (int ii = 0; ii < threadNum; ii++) {//開threadNum個線程 
Thread t = new ImportThread(c); 
t.start(); 
} 
while(true){//等待所有子線程執(zhí)行完 
if(!c.hasNext()) break; 
} 
System.out.println(Thread.currentThread().getName() + "結(jié)束.");//打印結(jié)束標(biāo)記 

打印結(jié)果: 

 main開始 
Thread-2開始... 
Thread-1開始... 
Thread-0開始... 
Thread-3開始... 
Thread-5開始... 
Thread-4開始... 
Thread-5結(jié)束. 還有5 個線程 
Thread-1結(jié)束. 還有4 個線程 
Thread-4結(jié)束. 還有3 個線程 
Thread-2結(jié)束. 還有2 個線程 
Thread-3結(jié)束. 還有1 個線程 
Thread-0結(jié)束. 還有0 個線程 
main結(jié)束. 

更簡單的方法:使用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();//線程結(jié)束時計數(shù)器減1 
System.out.println(Thread.currentThread().getName() + "結(jié)束. 還有" + 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();//等待所有子線程執(zhí)行完 
System.out.println(Thread.currentThread().getName() + "結(jié)束.");//打印結(jié)束標(biāo)記 

打印結(jié)果: 

main開始 
Thread-1開始... 
Thread-0開始... 
Thread-2開始... 
Thread-3開始... 
Thread-4開始... 
Thread-5開始... 
Thread-0結(jié)束. 還有5 個線程 
Thread-1結(jié)束. 還有4 個線程 
Thread-4結(jié)束. 還有3 個線程 
Thread-2結(jié)束. 還有2 個線程 
Thread-5結(jié)束. 還有1 個線程 
Thread-3結(jié)束. 還有0 個線程 
main結(jié)束.

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • 詳解Spring Boot 中實現(xiàn)定時任務(wù)的兩種方式

    詳解Spring Boot 中實現(xiàn)定時任務(wù)的兩種方式

    這篇文章主要介紹了Spring Boot 中實現(xiàn)定時任務(wù)的兩種方式,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • java開源調(diào)度如何給xxljob加k8s執(zhí)行器

    java開源調(diào)度如何給xxljob加k8s執(zhí)行器

    這篇文章主要介紹了java開源調(diào)度如何給xxljob加一個k8s執(zhí)行器,?xxljob?在設(shè)計上,抽象出了執(zhí)行器的接口,所以實現(xiàn)一個語言的執(zhí)行器并不復(fù)雜,這里主要探索下,如何利用k8s的pod?的能力,使用?xxljob?調(diào)度?pod?運行,實現(xiàn)一個通用的和語言無關(guān)的執(zhí)行器
    2022-02-02
  • Spring Boot下的Job定時任務(wù)

    Spring Boot下的Job定時任務(wù)

    編寫Job定時執(zhí)行任務(wù)十分有用,能解決很多問題,這次實習(xí)的項目里做了一下系統(tǒng)定時更新三方系統(tǒng)訂單狀態(tài)的功能,這里用到了Spring的定時任務(wù)使用的非常方便,下面總結(jié)一下如何使用,感興趣的朋友參考下吧
    2017-05-05
  • java實現(xiàn)HttpClient異步請求資源的方法

    java實現(xiàn)HttpClient異步請求資源的方法

    這篇文章主要介紹了java實現(xiàn)HttpClient異步請求資源的方法,實例分析了java基于http協(xié)議實現(xiàn)異步請求的技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-07-07
  • Java實戰(zhàn)入門之雙色球彩票小游戲

    Java實戰(zhàn)入門之雙色球彩票小游戲

    這篇文章主要介紹了Java實戰(zhàn)入門之雙色球彩票,文中有非常詳細(xì)的代碼示例,對正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下
    2021-04-04
  • 如何基于JavaFX開發(fā)桌面程序

    如何基于JavaFX開發(fā)桌面程序

    這篇文章主要介紹了如何基于JavaFX開發(fā)桌面程序,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-11-11
  • Java內(nèi)存模型相關(guān)知識總結(jié)

    Java內(nèi)存模型相關(guān)知識總結(jié)

    這篇文章主要介紹了Java內(nèi)存模型相關(guān)知識總結(jié),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-10-10
  • springboot整合log4j的踩坑實戰(zhàn)記錄

    springboot整合log4j的踩坑實戰(zhàn)記錄

    log日志的重要性不言而喻,所以我們需要在系統(tǒng)內(nèi)根據(jù)實際的業(yè)務(wù)進(jìn)行日志的整合,下面這篇文章主要給大家介紹了關(guān)于springboot整合log4j的踩坑實戰(zhàn)記錄,文中通過示例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-04-04
  • SpringAOP 設(shè)置注入的實現(xiàn)步驟

    SpringAOP 設(shè)置注入的實現(xiàn)步驟

    這篇文章主要介紹了SpringAOP 設(shè)置注入的實現(xiàn)步驟,幫助大家更好的理解和學(xué)習(xí)使用Spring框架,感興趣的朋友可以了解下
    2021-05-05
  • SpringBoot統(tǒng)一接口返回及全局異常處理高級用法

    SpringBoot統(tǒng)一接口返回及全局異常處理高級用法

    這篇文章主要為大家介紹了SpringBoot統(tǒng)一接口返回及全局異常處理高級用法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06

最新評論