start() 和 run()
start()
- 調用start方法,只是通知 jvm有一個線程要啓動,讓其在有空的時候啓動線程,至於何時啓動線程並不是start能決定的,最終啓動線程的時間點是由線程調度器決定的。所以線程啓動的順序並不是由調用start方法的順序決定的,這也說明了爲什麼有時候後調用start方法的線程會先啓動。(start只負責通知 jvm啓動,具體什麼時候啓動由線程調度器說了算)
- 調用start方法,涉及兩個線程,一個是主線程,即調用start方法的線程,另一個是要啓動的線程(新創建的線程)。
- start方法的執行流程:
- (1)檢查線程狀態,只有在new狀態下的線程才能繼續,否則拋出IllegalThreadStateException(在運行中或者已經結束的線程,都不能再次啓動);
- (2)被加入線程組;
- (3)調用 start0() 方法啓動線程;
注意:
(1)start方法是被synchronized修飾的方法,可以保證線程安全。
(2)由 jvm 創建的main方法線程和system組線程,並不會通過start來啓動。
Thread.java 中start方法的源碼如下:
public synchronized void start() {
// 如果線程不是"新建狀態(new)",則拋出異常!
if (threadStatus != 0)
throw new IllegalThreadStateException();
// 將線程添加到ThreadGroup中
group.add(this);
boolean started = false;
try {
// 通過start0()啓動線程
start0();
// 設置started標記
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}
start()實際上是通過本地方法start0()啓動線程的。而start0()會新運行一個線程,新線程會調用run()方法。
private native void start0();
run()
如果直接調用 run() ,那麼 run() 只是一個普通的方法而已,和線程的生命週期無關,程序中依然只有主線程這一個線程,其程序執行路徑還是隻有一條,還是要順序執行,還是要等待run方法體執行完畢後纔可繼續執行下面的代碼,這些就沒有達到實現多線程的目的。
Thread.java中run的源碼如下:
public void run() {
if (target != null) {
target.run();
}
}
target是一個Runnable接口的實現類的對象。run()就是直接調用Thread線程的Runnable實現類對象的run()方法,並不會新建一個線程。
兩者區別及總結
- start() : 用start方法來啓動線程,真正實現了多線程運行,其無需等待run方法體代碼執行完畢而直接繼續執行下面的代碼。通過調用Thread類的start()方法來啓動一個線程,這時此線程處於就緒(可運行)狀態,並沒有運行,一旦得到cpu時間片,就開始執行run()方法,這裏方法 run()稱爲線程體,它包含了要執行的這個線程的內容,run方法運行結束,此線程隨即終止;
- run():run()方法只是類的一個普通方法而已,如果直接調用Run方法,程序中依然只有主線程這一個線程,其程序執行路徑還是隻有一條,還是要順序執行,還是要等待run方法體執行完畢後纔可繼續執行下面的代碼,這樣就沒有達到寫線程的目的。
start() 纔是真正啓動一個線程的方法,啓動線程不能直接調用run方法,應該調用start方法,來間接地調用run方法啓動線程。
/**
* 對比start和run方法兩種方式啓動線程
*/
public class StartAndRunMethod {
public static void main(String[] args) {
//使用lambdab表達式創建Runnable接口實現類的實例
Runnable runnable = ()->{
System.out.println(Thread.currentThread().getName());
};
/*
直接調用run方法,那麼這時run方法只是一個普通的方法而已,
程序中依然只有主線程一個線程,所以這裏執行的是主線程(main)
*/
runnable.run();//這樣並不是執行新建的線程,這裏執行的是主線程(main)
/*
調用start可能並不會立馬啓動線程,start只是告訴jvm有一個線程要啓動,
讓其有空的時候啓動。
最終決定線程的啓動時間點是由線程調度器決定。
*/
new Thread(runnable).start();
}
}
運行結果:
main
Thread-0
參考:
Java Thread 的 run() 與 start() 的區別
Java多線程系列–“基礎篇”03之 Thread中start()和run()的區別