對於原先『單工式』程式開發的技術人員而言,『多執行緒』是一項 Java的全新特色,也就是在每一個行程(process)中包含多個執行緒(Thread),因為多執行緒應用程式將程式分割成一些獨立的工作,在運用得當的應用程式中,多執行緒可以大幅提升效能。
何謂執行緒(thread)
在說明執行緒前,讓我們先來了解什麼是行程(process)。作業系統在執行一個應用程式時,正在執行的應用程式稱為一個行程,系統會分配相對的系統資源與CPU時間,執行另一個應用程式時,則是另一個行程與資源分配的產生,同時會有對應的CPU時間。在執行應用程式時,行程與資源各自獨立才不會發生應用程式間相互干擾的現象。
CPU時間只有在程式執行的狀態才能取得,但不見得每一個應用程式都能被配置到100%的CPU時間。為了充份使用CPU時間,將暫時閒置的CPU時間用在執行應用程式的其他工作上,便是執行緒的概念。以往應用程式在一個行程中只能處理一件事情,現在利用執行緒可使一個應用程式在同一時期能執行多項工作,以達到程式多工。
多執行緒的程式的語法不難卻很難控制,因為相較於單工的應用程式,其困難度與複雜度皆增加許多,例如執行緒的執行先後順序與資源維護在程式控制上便是一大考驗,控制得宜可提昇程式效能,控制不好反而使執行效能比單工程式還低。
程式中一次可以處理多個執行緒,不過在同一個時間點真正執行的只有一個(這是指單一CPU的系統而言,因為大部分的PC只有一顆CPU)。也就是說,雖然程式可以一次處理多個執行緒,但真正執行的時候一次只有一個執行緒在執行(Running),其他執行緒則在Runnable區塊中等待。執行緒的執行先後順序也會依照執行緒的優先權來判定,其他的則仍然在Runnable區塊中等待下一次優先權的判定。
圖1-說明了執行緒的工作流程:
1. 執行緒(New Thread)經由start()方法進入Runnable pool中準備執行。
2. 在Runnable pool中的每個執行緒都有自身的優先權及時間順序。
3. 再由Scheduler(排程器)進行排程。
4. 經過排列後將選出來的執行緒丟入Running中執行。
5. 此時執行緒會觸發Run()方法,並執行實作內容(寫在Run()內的程式碼)。
6. 執行完畢或程式中呼叫了stop()方法時,執行緒便銷毀,不過其狀態還將會保留,只是銷毀的執行緒將無法再被執行。
7. 若執行緒未執行完成(例如取得的CPU時間已到卻還沒完成工作,或是程式呼叫了特定的方法)將會觸發Blocking event並進入封鎖區(Blocked)。
8. 被封鎖的執行緒解除封鎖(Unblocked)或者是程式中呼叫了resume()方法之後,將再進入Runnable pool中等待下一次執行。
9. 若程式中呼叫了yield()方法(讓與)則是將執行權先給其他執行緒執行,不過其本身仍然還是在Runnable中。
實作Java執行緒
每個應用程式至少要有一個執行緒(又稱之為主執行緒)來執行應用程式,為了讓程式在執行期間能執行多樣工作--也就是所謂的多執行緒應用程式(multi-thread)--必須利用其他方法產生額外的執行緒來執行程式。Java程式語言中提供了二種方法來撰寫執行緒程式:
1. 繼承Java.lang.Thread類別。
2. 實作Runnable介面。
二種方法皆可實作出多執行緒的程式,就看程式開發人員如何抉擇與使用。通常來說,利用Thread類別撰寫比較容易,用Runnable則可以忽略Java中單一繼承的限制(例如:若要在Applet中撰寫Thread程式,因為已經繼承了Applet類別所以必須要用Runnable介面來實作)。
利用Runnable介面來撰寫執行緒,程式較有一致性,當其他程式要用到時,可以有共同介面的標準,也比較符合物件導向(OO)的精神。