Java的多執行緒之等待其他執行緒執行完成,三匹馬的賽事

Java的多執行緒之等待其他執行緒執行完成,三匹馬的賽事

在設計多執行緒Threading程式時,常需要等待其他執行緒的執行結果,收集資訊後再進一步處理,本文章延續上一篇文章:

Java的多執行緒,以賽馬為例,學習如何繼承Thread與實作Runnable

在上一篇文章中,以main執行緒為第一匹馬,另外以Horse執行緒為第二匹馬,現在想讓main方法專心處理產生執行緒與計算賽馬名次等工作,因此,改變為三匹馬都以Horse執行緒來執行,在main方法中產生三個Horse執行緒物件,利用Thread的方法setName()給予三匹馬執行緒名稱(h1,h2,h3),main方法執行到最後時,印出「main執行緒結束」:

sleep方法

為了方便觀察Horse執行緒的執行結果,將原for迴圈改為讓執行緒睡覺2秒鐘,可使用Thread的方法sleep(long millis),共2000毫秒,sleep方法使用時必須以try…catch處理被意外中斷的例外InterruptedException:

執行Racing3類別的結果如下(每次結果有可能不一樣):

main執行緒結束
h1到達終點
h3到達終點
h2到達終點

發現一個問題了嗎?就是main執行緒是三匹馬執行緒的發起者,但它卻比三匹馬執行緒還要早結束,若是如此,我們將無法在三匹馬跑出結果時印出到達順序,如何能讓main執行緒等待三匹馬執行緒都結束後,才繼續往後執行呢?

如果讓main執行緒進入睡眠一段時間,雖然可以在睡醒時進行後續的動作,但如果睡覺時間不夠準確,或是三匹馬的執行緒完成時間是未知時,sleep()方法也就不適合用來等待其他「子執行緒」,因此,可以利用join()方法達到等待其他執行緒完成後,再進行後續的動作。

join()方法-等待

Thread類別的方法join(),可以用來等待該執行緒完成,使用join()方法時,和sleep()方法一樣,必須以try…catch處理被意外中斷的例外InterruptedException,如下:

觀察執行結果可發現,main執行緒會等待三匹馬執行緒都完成後,才會繼續第21行的執行:

h2到達終點
h3到達終點
h1到達終點
main執行緒結束

結算賽馬的名次

瞭解如何利用join()方法來等待子執行緒之後,先訂定一個放置三匹馬的集合rank,第一匹到達的馬可以進入到rank集合的第1個位置,第二匹到達的馬則進入到rank集合的第2的位置,以此類推。使用java.util.ArrayList做為集合類別,新增一類別Racing4來設計此功能:

import java.util.ArrayList;
import java.util.List;

public class Racing4 {
    public static void main(String[] args) {
        List<RankHorse> rank = new ArrayList<>();
        RankHorse h1 = new RankHorse(rank);
        RankHorse h2 = new RankHorse(rank);
        RankHorse h3 = new RankHorse(rank);
        h1.setName("h1");
        h2.setName("h2");
        h3.setName("h3");
        h1.start();
        h2.start();
        h3.start();
        try {
            h1.join();
            h2.join();
            h3.join();
        } catch (InterruptedException e) {
            System.out.println("執行緒被中斷");
        }
        System.out.println(rank);
        System.out.println("main執行緒結束");
    }
}

上述程式碼第7行,新增一個List物件rank,而且以「一般化」限定rank集合裏只能放置RankHorse物件,第8-10行則利用RankHorse的建構子將rank物件傳遞給執行緒類別RankHorse內部使用,最後在第24行依序印出rank集合內的所有物件(三匹馬)。因此,我們還要依照先前Horse類別的模式,再設計RankHorse類別,使其擁有排名的功能,範例程式如下:

import java.util.List;

public class RankHorse extends Thread {
    List<RankHorse> rank;
    public RankHorse(List<RankHorse> rank){
        this.rank = rank;
    }

    @Override
    public void run() {
        try {
            sleep(2000);
            System.out.println(getName() + "到達終點");
            //放進rank中
            rank.add(this);
        } catch (InterruptedException e) {
            System.out.println(getName() + "被中斷了");
        }
    }
}

上述程式的第4行,定義了成員rank,第6-8行則新增了建構子,以接收Racing4所傳來的rank物件,最後,等到此匹馬到達終點時,第17行將自己放入rank集合中,若此匹馬是第一名到達,將會放置在第一位。

Racing4類別的執行結果如下,可以看到rank集合內依照到達順序的三匹馬:

 

h2到達終點
h3到達終點
h1到達終點
[Thread[h2,5,], Thread[h3,5,], Thread[h1,5,]]
main執行緒結束

集合內的每匹RankHorse的h1,h2,3是執行緒的名稱,接著逗號後跟著該執行緒的優先權值,預設是5,有關執行優先權之後再另以文章介紹。

版權聲明

本文章授權範圍僅限綠豆湯網站使用,除Facebook之類社群等未更改本文章出處之分享行為不在此限,其他個人或公司未經作者同意,不得任意將本文章內容轉載至其他網站,或以任何形式重製,為以免觸犯著作權法,請尊重作者之智慧財產權。

相關文章:

Hank Tom

專長為程式語言、雲端服務開發,Linux系統管理, 任職:利拓科技 技術長,海林行動科技 技術總監 輔仁大學 兼任助理教授 , 為 Android高效入門>深度學習、CentOS 7建置、管理與伺服器架設實戰、Java網路程式設計、雲端網頁程式設計-Google App Engine應用實作 等書作者

發佈留言

×
×

Cart