start方法和run方法比較 很多人包括我自己也以前也認為run和start方法都可以啟動一個線程,並且兩者的功能都差不多,然後在學習的過程中認識到這是錯誤的,他們之間是 截然不同 的。先來看一段演示代碼: 輸出結果: 可以看到, 執行run方法的線程是主線程,而執行start方法的才是一個新的子 ...
start方法和run方法比較
很多人包括我自己也以前也認為run和start方法都可以啟動一個線程,並且兩者的功能都差不多,然後在學習的過程中認識到這是錯誤的,他們之間是截然不同的。先來看一段演示代碼:
/**
* @author Chen
* @Description start()和run()方法比較
* @create 2019-11-05 22:01
*/
public class StartAndRunMethod {
public static void main(String[] args) {
//使用run方法
Runnable runnable = ()-> System.out.println(Thread.currentThread().getName());
runnable.run();
//使用start方法
new Thread(runnable).start();
}
}
輸出結果:
main
Thread-0
可以看到,執行run方法的線程是主線程,而執行start方法的才是一個新的子線程。
start方法解讀
我們都知道start方法就是啟動一個新線程,其實真是情況是start方法執行過程中會涉及到兩個線程,一個是主線程,另一個是新的子線程,當調用start方法是,子線程並不會馬上啟動起來,子線程會獲取除了cpu以外的一些資源,進入就狀態,等待CPU的調用。至於什麼時候調用,這個就不是我們所能決定的了,而是線程調度器來決定的。所以有一些先運行start方法的線程可能會在比後調用start方法的線程啟動的慢。
當我們重覆調用兩次start方法會發生什麼?
會拋出一個異常IllegalThreadStateException(非法的線程狀態),其實線程一旦執行,就會進入runnable狀態,一旦執行完畢,就會進入結束狀態,不會在返回回去。
接下來我們在來仔細看看start()
,瞭解一下它執行的過程中到底幹了什麼。
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
在start()
中,首先會檢查線程的狀態,判斷threadStatus
是不是等於0,也就是判斷是不是一個新啟動的線程,這是執行兩次start()
拋出異常的原因。(線上程剛剛被初始化的時候預設的狀態為0)
然後又做了一個加入線程組這個行為,然後又執行了個start0的native方法。
run方法解讀
其實run方法比較簡單,只有三行代碼:如果target也就是傳入的介面不為空,就執行重寫的run方法的內容,否則就執行傳入的run方法的內容。
@Override
public void run() {
if (target != null) {
target.run();
}
}
所以當我們執行run方法的時候,它就會作為一個普通的方法,和我們自己寫的一樣,所以控制台列印出來的是一個主線程。
所以我們想啟動一個新線程不能直接調用run方法,而是應該調用start方法來間接調用run方法。