為什么啟動線程不直接調用run(),而要調用start(),如果調用兩次start()方法會有什么后果
1位工作6年的小伙伴去某里P6一面,被問到這樣一道面試題,說,為什么啟動一個線程不直接調用run()方法,而要調用start()方法來啟動,如果調用兩次start()會有什么后果?
如果,你被問到這樣一道面試,你能回答出來嗎?今天,我給大家來分享一下,我對這個問題的理解。
1、run()和start()的區(qū)別
首先回答為什么啟動線程不能直接調用run()方法,而要調用start()方法,我從以下4個方面來回答:
第1:start()方法是Java線程約定的內置方法,能夠確保代碼在新的線程上下文中運行。
第2:start()方法包含了觸創(chuàng)建新線程的特殊代碼邏輯。run()方法是我們自己寫的代碼,很顯然沒有這個能力。
第3:如果直接調用run()方法,那么它只是一個普通的方法調用,程序中依然只有一個主線程,并且只能順序執(zhí)行,需要等待run()方法執(zhí)行結束后才能繼續(xù)執(zhí)行后面的代碼。
第4:我們創(chuàng)建線程的目的是為了更充分地利用CPU資源,如果直接調用run()方法,就失去了創(chuàng)建線程的意義了。
2、調用兩次start()的后果
了解了run()方法和start()方法的區(qū)別,那如果調用兩次start()方法會有什么后果呢?在Java中,線程的start()方法只能被調用一次,如果第二次調用會拋出 IllegalThreadStateException,這是一種運行時異常,多次調用 start 被認為是編程錯誤。
在Java中,線程的運行狀態(tài)被定義成了5個枚舉值,分別是:
(1)新建(NEW),線程已經(jīng)創(chuàng)建好了,但是還沒有調用start()方法啟動。
(2)就緒(RUNNABLE),這個狀態(tài)下的線程可能正在運行,也可能還在就緒隊列里面,等待系統(tǒng)分配CPU資源。
在操作系統(tǒng)中,會額外區(qū)分一種狀態(tài)叫做RUNNING,但是從 Java API 的角度,并不能表示出來。
(3)阻塞(BLOCKED),表示線程處于等待Monitor Lock的狀態(tài)。
(4)等待(WAITING),表示線程處于條件等待狀態(tài),當觸發(fā)條件后會喚醒。比如wait/notify等。
(5)計時等待(TIMED_WAIT),它和WAITING狀態(tài)是一樣的,只是多了一個超時條件觸發(fā)機制。
(6)終止(TERMINATED),表示線程執(zhí)行結束。
在Java API 中,影響線程運行狀態(tài)的因素,如圖所示:
在我們第一次調用 start() 方法的時候,線程可能處于終止或者其他非 NEW的狀態(tài),再次調用start()方法的時候,相當于讓這個正在運行的線程重新運行一遍。不管是從線程安全的角度來看,還是從線程本身的執(zhí)行邏輯來看,它都是不合理的。
因此,為了避免這個問題出現(xiàn),Java會先去判斷當前線程的運行狀態(tài)。
好了,以上就是我對Java線程的start()方法和run()方法的理解。