一個應用程式或行程(Process)可以向作業系統取得多個執行緒(threads),多個執行緒可以模擬出平行處理的效果。一個具備單一(此處的CPU僅考慮單核心)的系統,事實上同一時間只能執行一件事,但如果將一個CPU的執行時間切割為很小的單位,將這些單位分給多個行程去使用,就可以模擬出多工(multi-task)的效果,如下圖。
一個可以執行的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類別。
如何使用java.lang.Thread類別來產生第二個執行緒呢? 下一篇將從【繼承Thread類別】開始實作一個賽馬程式。
下一篇: Java執行緒,以賽馬為例,學習如何繼承Thread與實作Runnable
版權聲明
本文章授權範圍僅限綠豆湯網站使用,除Facebook之類社群等未更改本文章出處之分享行為不在此限,其他個人或公司未經作者同意,不得任意將本文章內容轉載至其他網站,或以任何形式重製,為以免觸犯著作權法,請尊重作者之智慧財產權。
請問繼承 thread與 Runnable使用區別,何時該用Thread ,又何時該實作 Runnable
如果你想要變成執行緒的類別(不是全新的)原本已繼承父類別了,那就只好實作Runnable了。