先來看下結論:正确啟動線程的方式是使用start()方法,而不是使用run()方法。
“Talk is cheap. Show me the code”,用代碼說話:分别調用run()方法和start()方法,列印輸出線程的名字。
運作結果:
如果代碼是這樣的,執行結果有什麼不同呢?
執行結果為:
是不是有點意外?然而,這就是真相。其實也不難解釋。
我們說的并發是什麼,并發不就是線程之間的運作互不幹擾嘛?當JVM啟動的時候,建立一個mian線程來運作main()方法。當執行到“new Thread(runnable).start();”的時候main線程會建立一個Thread-0線程。main線程和Thread-0線程的執行時互不相幹的,是以可能不會出現“main-Thread-0-main”的結果。
我執行了n(n>20)次,運作結果依然如上圖所示,沒有出現“main-Thread-0-main”。這是為什麼呢?回憶一下線程的生命周期, Java中,線程(Thread)定義了6種狀态: NEW(建立)、RUNNABLE(可執行)、BLOCKED(阻塞)、WAITING(等待)、TIMED_WAITING(限時等待)、TERMINATED(結束)。當調用了start()方法之後,線程進入RUNNABLE狀态,RUNNABLE的意思是可運作,即可能正在執行,也可能沒有正在執行。那調用了start方法之後,什麼時候執行呢?調用start()方法之後,我們隻是告訴JVM去執行這個線程,至于什麼時候運作是由線程排程器來決定的。從作業系統層面,其實調用start()方法之後要去擷取作業系統的時間片,擷取到才會執行。這個問題,可以對比思考“ thread.start()調用之後線程會立刻執行嗎?”更多可以參考:從源碼解讀線程(Thread)和線程池(ThreadPoolExecutor)的狀态
start()源碼如下:
可以看到,start()方法被synchronized關鍵字修飾,保證了線程安全。啟動流程分為下面三個步驟:
首先會檢查線程狀态,隻有threadStatus == 0(也就是線程處于NEW狀态)狀态下的線程才能繼續,否則會抛出IllegalThreadStateException。
将線程加入線程組
調用native方法——start0()方法啟動線程。
會抛出IllegalThreadStateException,具體原因可以用源碼和線程啟動步驟進行說明。
start()才是真正啟動一個線程,而如果直接調用run(),那麼run()隻是一個普通的方法而已,和線程的生命周期沒有任何關系。用代碼驗證一下:
在上面代碼中,直接調用run()方法,run()隻是一個普通的方法,由目前線程——main線程執行。start()才是真正啟動一個線程——Thread0,run()方法由線程Thread0執行。
可以看start()方法的注釋部分:
也就是說當該線程開始執行的時候,Java虛拟機會自動調用該線程的run()方法。
由于部落客也是在攀登的路上,文中可能存在不當之處,歡迎各位多指教! 如果文章對您有用,那麼請點個”推薦“,以資鼓勵!