一 個Java程式啟動後,預設只有一個流程,也就是從程式進入點main開始的流程,這個流程稱之為主執行緒(main thread),如果你只使用主執行緒要「同時」作某件事,例如,在一個視窗畫面上「同時」畫兩排平行的圓,一排在高度為10,一排在高度為50的地方的 話,程式撰寫起來就有些麻煩,基本上就是先在高度10畫個圓,再迅速於高50畫圓,平移後再於高度10畫個圓,再於高度50畫個圓....依此進行下去:
如果你可以有兩個物件,一個只負責在高度10平移畫圓,一個只在高度50平移畫圓,那麼撰寫程式時就簡單的多了,分別在這兩個物件的「程式執行點」中撰寫個別的流程就可以了,這樣的物件在Java中稱之為「可執行物件」,一個可執行的物件可以建立一個執行緒(Thread)來執行它:
在Java中要實作可執行物件,可以實作Runnable介面,這個介面只有一個run()方法要實作,run()方法就是可執行物件的「執行進入點」,run()方法中實作的內容,就是一個獨立的執行流程。
public class CirclePainter implements Runnable {
public CirclePainter(int x, int y, int r, int offset) {
....
}
public void run() {
while(...) {
.. 在(x, y) 畫半徑 r 的 圓
... 平移 offset
}
}
}
public CirclePainter(int x, int y, int r, int offset) {
....
}
public void run() {
while(...) {
.. 在(x, y) 畫半徑 r 的 圓
... 平移 offset
}
}
}
JVM本身是個虛擬的系統,.class檔案就是其可執行檔,預設上,JVM只安裝一個虛擬的CPU來執行程式,這個虛擬的CPU就是主執行緒,執行流程的程式進入點就是main()方法。
如果你想在虛擬的系統上多裝幾個虛擬的CPU,那就是建立多個執行緒,給每個執行緒可執行的程式碼,然後啟動執行緒。以Java程式碼來示範的話:
Thread painterThread1 = new Thread(new CiclePainter(50, 10, 10));
Thread painterThread2 = new Thread(new CiclePainter(50, 50, 10));
painterThread1.start();
painterThread2.start();
Thread painterThread2 = new Thread(new CiclePainter(50, 50, 10));
painterThread1.start();
painterThread2.start();
多加裝的虛擬CPU,其所執行的程式碼,就是可執行物件所定義的程式碼,執行的進入點就是run()方法,一旦加裝的虛擬CPU執行完run()方法,這個虛擬CPU就作廢準備回收,也就是執行緒物件一旦執行完run()方法,就不再被使用而等著被垃圾回收,你不可以嘗試重新啟動執行完run()方法的執行緒物件,這會發生例外。
Thread物件啟動後,會執行可執行物件的run()方法,這是定義在Thread的run()方法中,實際上,Thread本身也實作了Runnable介面:
public class Thread implements Runnable {
...
private Runnable target;
....
public void run() {
if (target != null) {
target.run();
}
}
...
}
...
private Runnable target;
....
public void run() {
if (target != null) {
target.run();
}
}
...
}
你 也可以直接繼承Thread後,重新定義其run()方法,但需注意繼承有「是一種」(is a)的關係,也就是你繼承Thread後的類別,必然「是一種」執行緒,而且不再能繼承自其它類別,正如繼承Thread後就「是一種」執行緒,會繼承 Thread的目的,通常是為了利用Thread已定義的程式碼。