最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

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

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

long tStart = System.currentTimeMillis(); 
System.out.println(Thread.currentThread().getName() + "開(kāi)始");//打印開(kāi)始標(biāo)記 
for (int ii = 0; ii < threadNum; ii++) {//開(kāi)threadNum個(gè)線程 
Runnable r = new Runnable(){ 
@Override 
public void run(){ 
System.out.println(Thread.currentThread().getName() + "開(kāi)始"); 
//做一些事情... ... 
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("總共用時(shí):"+ (tEnd - tStart) + "millions"); 

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

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

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

public class ImportThread extends Thread { 
private static List<Thread> runningThreads = new ArrayList<Thread>(); 
public ImportThread() { 
} 
@Override 
public void run() { 
regist(this);//線程開(kāi)始時(shí)注冊(cè) 
System.out.println(Thread.currentThread().getName() + "開(kāi)始...");//打印開(kāi)始標(biāo)記 
//做一些事情... ... 
unRegist(this);//線程結(jié)束時(shí)取消注冊(cè) 
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);//通過(guò)判斷runningThreads是否為空就能知道是否還有線程未執(zhí)行完 
} 
} 

主線程中代碼: 

long tStart = System.currentTimeMillis(); 
System.out.println(Thread.currentThread().getName() + "開(kāi)始");//打印開(kāi)始標(biāo)記 
for (int ii = 0; ii < threadNum; ii++) {//開(kāi)threadNum個(gè)線程 
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("總共用時(shí):"+ (tEnd - tStart) + "millions"); 

打印的結(jié)果是: 

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

總共用時(shí):20860millions 

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

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

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

MyCountDown類(lèi) 
 

  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類(lèi) 

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

主線程中 

System.out.println(Thread.currentThread().getName() + "開(kāi)始");//打印開(kāi)始標(biāo)記 
MyCountDown c = new MyCountDown(threadNum);//初始化countDown 
for (int ii = 0; ii < threadNum; ii++) {//開(kāi)threadNum個(gè)線程 
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開(kāi)始 
Thread-2開(kāi)始... 
Thread-1開(kāi)始... 
Thread-0開(kāi)始... 
Thread-3開(kāi)始... 
Thread-5開(kāi)始... 
Thread-4開(kāi)始... 
Thread-5結(jié)束. 還有5 個(gè)線程 
Thread-1結(jié)束. 還有4 個(gè)線程 
Thread-4結(jié)束. 還有3 個(gè)線程 
Thread-2結(jié)束. 還有2 個(gè)線程 
Thread-3結(jié)束. 還有1 個(gè)線程 
Thread-0結(jié)束. 還有0 個(gè)線程 
main結(jié)束. 

更簡(jiǎn)單的方法:使用java.util.concurrent.CountDownLatch代替MyCountDown,用await()方法代替while(true){...}

ImportThread類(lèi) 

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() + "開(kāi)始..."); 
//Do somethings 
threadsSignal.countDown();//線程結(jié)束時(shí)計(jì)數(shù)器減1 
System.out.println(Thread.currentThread().getName() + "結(jié)束. 還有" + threadsSignal.getCount() + " 個(gè)線程"); 
} 
} 

主線程中 

CountDownLatch threadSignal = new CountDownLatch(threadNum);//初始化countDown 
for (int ii = 0; ii < threadNum; ii++) {//開(kāi)threadNum個(gè)線程 
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開(kāi)始 
Thread-1開(kāi)始... 
Thread-0開(kāi)始... 
Thread-2開(kāi)始... 
Thread-3開(kāi)始... 
Thread-4開(kāi)始... 
Thread-5開(kāi)始... 
Thread-0結(jié)束. 還有5 個(gè)線程 
Thread-1結(jié)束. 還有4 個(gè)線程 
Thread-4結(jié)束. 還有3 個(gè)線程 
Thread-2結(jié)束. 還有2 個(gè)線程 
Thread-5結(jié)束. 還有1 個(gè)線程 
Thread-3結(jié)束. 還有0 個(gè)線程 
main結(jié)束.

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

相關(guān)文章

  • java制作簡(jiǎn)單的坦克大戰(zhàn)

    java制作簡(jiǎn)單的坦克大戰(zhàn)

    坦克大戰(zhàn)是我們小時(shí)候玩紅白機(jī)時(shí)代的經(jīng)典游戲,看到有不少小伙伴都使用各種語(yǔ)言實(shí)現(xiàn)了一下,手癢癢,也使用java做的一個(gè)比較簡(jiǎn)單的坦克大戰(zhàn),主要面向于學(xué)過(guò)Java的人群,與學(xué)了一段時(shí)間的人,有利于面向?qū)ο笏枷氲奶岣?,推薦給大家。
    2015-03-03
  • springboot實(shí)用配置詳細(xì)圖文教程

    springboot實(shí)用配置詳細(xì)圖文教程

    SpringBoot從本質(zhì)上來(lái)說(shuō)就是Spring,它通過(guò)了一些自己的特性幫助我們簡(jiǎn)化了Spring應(yīng)用程序的開(kāi)發(fā),下面這篇文章主要給大家介紹了關(guān)于springboot實(shí)用配置的相關(guān)資料,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-05-05
  • Java后端接口中提取請(qǐng)求頭中的Cookie和Token的方法

    Java后端接口中提取請(qǐng)求頭中的Cookie和Token的方法

    在現(xiàn)代 Web 開(kāi)發(fā)中,HTTP 請(qǐng)求頭(Header)是客戶(hù)端與服務(wù)器之間傳遞信息的重要方式之一,本文將詳細(xì)介紹如何在 Java 后端(以 Spring Boot 為例)中提取請(qǐng)求頭中的 Cookie 和 Token,并提供完整的代碼示例和優(yōu)化建議,需要的朋友可以參考下
    2025-01-01
  • PowerJob?AbstractSqlProcessor方法工作流程源碼解讀

    PowerJob?AbstractSqlProcessor方法工作流程源碼解讀

    這篇文章主要為大家介紹了PowerJob?AbstractSqlProcessor方法工作流程源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • spring boot+mybatis 多數(shù)據(jù)源切換(實(shí)例講解)

    spring boot+mybatis 多數(shù)據(jù)源切換(實(shí)例講解)

    下面小編就為大家?guī)?lái)一篇spring boot+mybatis 多數(shù)據(jù)源切換(實(shí)例講解)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-09-09
  • java實(shí)現(xiàn)斐波那契數(shù)列的3種方法

    java實(shí)現(xiàn)斐波那契數(shù)列的3種方法

    這篇文章主要介紹了java實(shí)現(xiàn)斐波那契數(shù)列的3種方法,有需要的朋友可以參考一下
    2014-01-01
  • 詳解在spring boot中配置多個(gè)DispatcherServlet

    詳解在spring boot中配置多個(gè)DispatcherServlet

    本篇文章主要介紹了詳解在spring boot中配置多個(gè)DispatcherServlet,具有一定的參考價(jià)值,有興趣的可以了解一下。
    2017-03-03
  • Java springboot 配置文件與多環(huán)境配置與運(yùn)行優(yōu)先級(jí)

    Java springboot 配置文件與多環(huán)境配置與運(yùn)行優(yōu)先級(jí)

    這篇文章主要介紹了Java springboot如何配置文件,進(jìn)行多環(huán)境配置,以及運(yùn)行優(yōu)先級(jí),感興趣的小伙伴可以借鑒一下
    2023-04-04
  • 詳解java中float與double的區(qū)別

    詳解java中float與double的區(qū)別

    這篇文章主要介紹了JAVA中float與double的區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • 解讀springboot配置mybatis的sql執(zhí)行超時(shí)時(shí)間(mysql)

    解讀springboot配置mybatis的sql執(zhí)行超時(shí)時(shí)間(mysql)

    這篇文章主要介紹了解讀springboot配置mybatis的sql執(zhí)行超時(shí)時(shí)間(mysql),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-01-01

最新評(píng)論

宜阳县| 原平市| 武乡县| 安吉县| 益阳市| 信丰县| 扶绥县| 石家庄市| 顺平县| 根河市| 深州市| 曲周县| 葫芦岛市| 阜南县| 禹州市| 陆河县| 望城县| 金门县| 石柱| 南昌县| 河曲县| 三门县| 辛集市| 民县| 信丰县| 当雄县| 阳新县| 都兰县| 临安市| 余江县| 武宁县| 河源市| 灵宝市| 潮州市| 曲阳县| 沙田区| 衢州市| 平陆县| 平舆县| 巴林右旗| 明光市|