Java 的多執行緒,由基礎開始認識 Threading

Java 的多執行緒,由基礎開始認識 Threading

基礎開始認識 Threading

 一個應用程式或行程(Process)可以向作業系統取得多個執行緒(threads),多個執行緒可以模擬出平行處理的效果。一個具備單一(此處的CPU僅考慮單核心)的系統,事實上同一時間只能執行一件事,但如果將一個 CPU 的執行時間切割為很小的單位,將這些單位分給多個行程去使用,就可以模擬出多工(multi-task)的效果,如下圖。

cpu process

 一個可以執行的 Java 類別,在 main 這個特別的方法被執行時,也就擁有了作業系統的一個執行緒,由 main 方法的開始到結束,都使用這個單一執行緒。因此,假如我想設計一個賽馬的程式,就只能讓一匹馬從起點跑到終點,如果想要設計出多匹馬一起跑,而且各自跑到終點,那就要使用多執行緒的功能。

 Java 語言中,java.lang.Thread 類別就是設計讓使用者向作業系統取得額外的執行緒,並在這個執行緒類別中,放入設計師想要做的工作,開發人員只需要繼承 Thread 類別即可讓新類別具備執行緒的能力。另外,若我們設計的類別已經繼承了某類別時,因 Java 語言單一繼承的限制性,而無法繼承 Thread 類別時,則可以利用 java.lang.Runnable 這個介面達到多執行緒的目的,本系列文章後續將說明如何利用 Thread 類別與 Runnable 介面來設計多執行緒的程式。

 為了要展示執行緒的效果,有時會在程式碼中使用大量的迴圈讓它不要執行慢一點,好看得出它的效用。當然,在練習時可以這麼做,但這只會在執行時增加不必要的 CPU 負荷。若要有停頓效果,應使用讓執行緒暫停的方法,如 sleep(50) 可讓執行緒進入休眠 50 毫秒,刻意使執行速度放慢,才能看出其差異。

執行緒

 一個程式在執行過程中可以擁多個執行緒,這些執行緒可以由開發人員決定而擁有不同層級的優先權(priority),而且,每個執行緒都有四種狀態:

  • 執行中(Running)
    • 執行緒正在執行當中。
  • 暫停(Suspended)
    • 暫停已在執行當中的執行緒,但可以讓它繼續執行(resume)。
  • 被阻擋(Blocked)
    • 執行緒因某個特定的資源被其他執行緒占用時,會進入等待的狀態。
  • 終止(Terminated)
    • 執行緒被終止或停止,但無法再繼續執行。

java.lang.Thread 類別的方法

 可以利用繼承 Thread 類別或實作 Runnable 介面來產生執行緒,Thread 類別設計了許多管理執行緒的方法,常用的方法有:

  • String getName()
    • 取得執行緒的名稱
  • void run()
    • 執行緒的主要工作內容
  • void start()
    • 啟動執行緒的方法
  • int getPriority()
    • 取得執行緒的優先權值
  • boolean isAlive()
    • 執行緒是否存活著?
  • void join()
    • 等待執行緒結束,進入終止狀態
  • void sleep(long millis)
    • 使執行緒進入睡眠狀態,傳入值為睡眠時間,單位是毫秒

main 方法也是個執行緒

 每個 Java 應用程式都擁有一個執行緒,因為 main 方法執行時,一定會產生一個執行緒(main thread),讀者可以在 main 方法區塊中,利用 Thread 類別的方法 currentThread() 便可得到目前的執行緒物件,如下程式範例,可取得執行緒的名稱(getName()),或改變該執行緒的名稱(setName()方法)。

public class ThreadName {
    public static void main(String[] args) {
        Thread thr = Thread.currentThread();
        System.out.println("目前執行緒名稱:"+thr.getName());
        thr.setName("DEMO");
        System.out.println("更改後的名稱:"+thr.getName());
    }
} 

 執行結果:

目前執行緒名稱:main
更改後的名稱:DEMO 

兩匹馬假賽跑

 若只有使用 main 方法來設計賽馬的程式,不能達到實際的需求,以下的程式利用 for 迴圈讓兩匹馬(整數 h1 與 h2)從 0 加到 5000,看那匹馬先到終點(5000):

public class RacingNG {
    public static void main(String[] args) {
        int h1 = 0;
        int h2 = 0;
        for (int i=0; i<5000; i++){
            h1++;
            h2++;
            System.out.println("H1:"+h1);
            System.out.println("H2:"+h2);
        }
    }
} 

 執行結果,每一次執行一定是 h1 先到達終點:

(省略)
H1:4996
H2:4996
H1:4997
H2:4997
H1:4998
H2:4998
H1:4999
H2:4999
H1:5000
H2:5000 

 每次執行結果都一樣是不符合實際需求的,因此,我們應該把 h2 的工作(從 0 加到 5000)「搬到」另一個執行緒去處理,讓 main 執行緒與新執行緒一起執行,要達到這個功能,我們需要的是 Thread 類別。

Horse thread

 如何使用 java.lang.Thread 類別來產生第二個執行緒呢? 下一篇將從【繼承Thread類別】開始實作一個賽馬程式。

版權聲明

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

發佈留言