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

網路程式經常使用到多執行緒程式設計,為讓初學者能夠輕鬆瞭解多執行緒的特色,以賽馬程式為範例,設計多執行緒的Java應用程式。依照內容順序實作,可瞭解到未使用多執行緒的問題與實作多執行緒的優點,並在最後進一步認識這個機制的特色與方法。
本篇為延續 Java的多執行緒,由基礎開始認識Threading ,請先認識執行緒的基礎。

繼承Thread類別

java.lang.Thread類別可以讓使用者向作業系統取得額外的執行緒,並在這個執行緒類別中,放入設計師想要做的工作。

設計執行緒類別

要產生一個執行緒得先要做好預先的設計工作,Thread類別中有個空的方法(裏面未有程式碼)叫做run(),開發人員可以新增一個類別並繼承Thread,再覆寫Thread的run()方法,將要執行的工作程式碼放在run()方法內,類別的架構如下圖。

產生執行緒類別並執行

上述的預先設計完成後擁有一個新的類別 Horse,將 Horse類別建構出來後,再呼叫其方法 start(),即可啟動這個執行緒,而這個執行緒將執行 run() 方法裏的工作。

package com.
public class Horse extends Thread{
  //覆寫Thread方法run()
  public void run(){
    //由1跑到5000
    int h = 0;
    for (int i=0; i<5000; i++){
      h++;
      System.out.println(getName()+":"+h);
    }
  }
}

接下來,設計一個新類別 Racing 類別,在未開始執行迴圈之前,生出Horse 類別的物件,再啟動這個執行緒:

public class Racing {
  public static void main(String[] args) {
    int h1 = 0;
    //產生Horse物件並啟動執行緒
    Horse h2 = new Horse();
    h2.start();
    for (int i=0; i<5000; i++){
      h1++;
      System.out.println("H1:"+h1);
    }
  }
}

程式碼與執行緒之間的示意圖如下:

多次執行結果不同

可以執行該程式多次,可看到執行結果的不同(每個人的結果可能不一樣),如下圖執行結果片段:
h2執行緒比main還早執行完成

(省略)
H1:4995
H1:4996
H1:4997
H1:4998
H1:4999
H1:5000
Thread-0:1496
Thread-0:1497
Thread-0:1498
Thread-0:1499
(省略)

main執行緒較h2早執行完成

(省略)
Thread-0:4998
Thread-0:4999
Thread-0:5000
H1:1053
H1:1054
H1:1055
H1:1056
H1:1057
(省略)

我們已設計一個新類別,並繼承Thread類別,然後覆寫了run()方法來產生執行緒,但有時候,一個已設計好的類別若已經繼承了其他父類別,而無法再繼承Thread類別時,則可以「實作Runnable介面」間接達成執行緒的設計。

實作Runnable介面

實作(implements)介面時,必須也要實作該介面的所有方法,Runnable介面的唯一方法就是run()方法,將上一段的Horse改用介面來實作,新類別為HorseRunnable,由於Runnable與Thread都將執行緒的工作放在run()方法,因此,除了類別定義時改採為實作介面外,其他大致相同,設計方式如範例程式。

public class HorseRunnable implements Runnable{
    public void run(){
        int h = 0;
        for (int i=0; i<5000; i++){
            h++;
            System.out.println(h);
        }
    }
}

啟動執行緒

要啟動實作Runnable介面的類別執行緒時,有些許的不同,利用三個步驟來啟動執行緒:

  1. 產生執行緒類別的物件
HorseRunnable h3 = new HorseRunnable();
  1. 利用Thread類別建構子中的其中一個可接收參數Runnable物件的建構子
Thread thr = new Thread( h3 );
  1. 呼叫Thread物件的start()方法
thr.start();

現在另設計一個Racing2類別,模擬兩匹馬的賽事,第二匹馬h2則是以HorseRunnable為執行緒,範例程式如下:

public class Racing2 {
    public static void main(String[] args) {
        int h1 = 0;
        //產生HorseRunnable物件並啟動執行緒
        HorseRunnable h2 = new HorseRunnable();
        Thread thr = new Thread(h2);
        thr.start();
        for (int i=0; i<5000; i++){
            h1++;
            System.out.println("H1:"+h1);
        }
    }
}

執行結果與Racing類別大致類同,只是HorseRunnable未印出”H2″字樣。
在以繼承Thread與實作Runnable兩種方法後,下一篇文章,將以三匹馬的賽事實作案例,進一步認識Thread類別的方法與控制執行緒的方法與活用。
後續文章:
Java的多執行緒之等待其他執行緒執行完成,三匹馬的賽事

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

2 Comments

  1. 寶大郎

    (1)Racing執行結果的2張圖是否貼反了?
    (2)為何我不論Racing或Racing2每次執行的結果都一樣呢?

    • 執行結果是對的,因為現在的電腦執行能力較好,可以試著加大迴圈數(如50000),才能看得出差異。

發佈回覆給「寶大郎」的留言 取消回覆

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *