Java中為什么start方法不能重復調(diào)用而run方法可以?
初學線程時,總是將 run 方法和 start 方法搞混,雖然二者是完全不同的兩個方法,但剛開始使用時很難分清,原因就是因為初次使用時效果貌似是一樣的,
如下代碼所示:
public static void main(String[] args) {
// 創(chuàng)建線程一
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("執(zhí)行線程一");
}
});
// 調(diào)用 run 方法
thread.run();
// 創(chuàng)建線程二
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
System.out.println("執(zhí)行線程二");
}
});
// 調(diào)用 start 方法
thread2.start();
}以上程序的執(zhí)行結果如下:

從上述結果可以看出,二者調(diào)用之后的執(zhí)行效果都是一樣,都可以成功執(zhí)行任務。但是,如果在執(zhí)行線程的時候,加上打印當前線程的名稱就能看出二者的不同了,
如下代碼所示:
public static void main(String[] args) {
// 創(chuàng)建線程一
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// 獲取到當前執(zhí)行線程
Thread currThread = Thread.currentThread();
System.out.println("執(zhí)行線程一,線程名:" + currThread.getName());
}
});
// 調(diào)用 run 方法
thread.run();
// 創(chuàng)建線程二
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
// 獲取到當前執(zhí)行線程
Thread currThread = Thread.currentThread();
System.out.println("執(zhí)行線程二,線程名:" + currThread.getName());
}
});
// 調(diào)用 start 方法
thread2.start();
}以上程序的執(zhí)行結果如下:

從上述結果我們可以看出:當調(diào)用 run 方法時,其實是調(diào)用當前主程序 main 來執(zhí)行方法體的;而調(diào)用 start 方法才是真正的創(chuàng)建一個新線程來執(zhí)行任務。
區(qū)別1
run 方法和 start 方法的第一個區(qū)別是:調(diào)用 start 方法是真正開啟一個線程來執(zhí)行任務,而調(diào)用 run 方法相當于執(zhí)行普通方法 run,并不會開啟新線程,
如下圖所示:

區(qū)別2
run 方法和 start 方法的第二個區(qū)別是:run 方法也叫做線程體,它里面包含了具體要執(zhí)行的業(yè)務代碼,當調(diào)用 run 方法時,會立即執(zhí)行 run 方法中的代碼(如果當前線程時間片未用完);而調(diào)用 start 方法時,是啟動一個線程并將線程的狀態(tài)設置為就緒狀態(tài)。也就是說調(diào)用 start 方法,并不會立即執(zhí)行。
區(qū)別3
因為 run 方法是普通方法,而普通方法是可以被多次調(diào)用的,所以 run 方法可以被調(diào)用多次;而 start 方法是創(chuàng)建新線程來執(zhí)行任務,因為線程只能被創(chuàng)建一次,所以它們的第三個區(qū)別是:run 方法可以被調(diào)用多次,而 start 方法只能被調(diào)用一次。
測試代碼如下:
// 創(chuàng)建線程一
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
// 獲取到當前執(zhí)行的線程
Thread currThread = Thread.currentThread();
System.out.println("執(zhí)行線程一,線程名:" + currThread.getName());
}
});
// 調(diào)用 run 方法
thread.run();
// 多次調(diào)用 run 方法
thread.run();
// 創(chuàng)建線程二
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
// 獲取到當前執(zhí)行的線程
Thread currThread = Thread.currentThread();
System.out.println("執(zhí)行線程二,線程名:" + currThread.getName());
}
});
// 調(diào)用 start 方法
thread2.start();
// 多次調(diào)用 start 方法
thread2.start();以上程序的執(zhí)行結果如下:

從上述結果可以看出,run 方法多次調(diào)用可用正常執(zhí)行,而第二次調(diào)用 start 方法時程序就報錯了,提示“IllegalThreadStateException”非法線程狀態(tài)異常。
為什么start不能被重復調(diào)用?
要找到這個問題的答案,就要查看 start 方法的實現(xiàn)源碼,它的源碼如下:

從 start 源碼實現(xiàn)的第一行,我們就可以得到問題的答案,因為 start 方法在執(zhí)行時,會先判斷當前線程的狀態(tài)是不是等于 0,也就是是否為新建狀態(tài) NEW,如果不等于新建狀態(tài),那么就會拋出“IllegalThreadStateException”非法線程狀態(tài)異常,這就是線程的 start 方法不能被重復調(diào)用的原因。 它的執(zhí)行過程是:當線程調(diào)用了第一個 start 方法之后,線程的狀態(tài)就會從新建狀態(tài) NEW,變?yōu)榫途w狀態(tài) RUNNABLE,此時再次調(diào)用 start 方法,JVM 就會判斷出當前的線程已經(jīng)不等于新建狀態(tài),從而拋出 IllegalThreadStateException 非法線程狀態(tài)異常。
總結
run 方法和 start 方法的主要區(qū)別如下:
- 方法性質(zhì)不同:run 是一個普通方法,而 start 是開啟新線程的方法。
- 執(zhí)行速度不同:調(diào)用 run 方法會立即執(zhí)行任務,調(diào)用 start 方法是將線程的狀態(tài)改為就緒狀態(tài),不會立即執(zhí)行。
- 調(diào)用次數(shù)不同:run 方法可以被重復調(diào)用,而 start 方法只能被調(diào)用一次。
start 方法之所以不能被重復調(diào)用的原因是,線程的狀態(tài)是不可逆的,Thread 在 start 的實現(xiàn)源碼中做了判斷,如果線程不是新建狀態(tài) NEW,則會拋出非法線程狀態(tài)異常 IllegalThreadStateException。?
到此這篇關于Java中為什么start方法不能重復調(diào)用而run方法可以?的文章就介紹到這了,更多相關start與run方法內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java編程實現(xiàn)快速排序及優(yōu)化代碼詳解
這篇文章主要介紹了Java編程實現(xiàn)快速排序及優(yōu)化代碼詳解,具有一定借鑒價值,需要的朋友可以了解下。2017-12-12
解決springboot接入springfox-swagger2遇到的一些問題
這篇文章主要介紹了解決springboot接入springfox-swagger2遇到的一些問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-07-07

