概要:new Thread 並不意味著已經建立了一個執行緒,只能說明建立一個類的物件例項而已。而真正建立執行緒的是start()方法,此方法將呼叫本地方法start0()建立本地執行緒,而Thread的run()方法其實是作為一個回撥函式被JVM建立的執行緒所呼叫。
構造方法與執行緒建立有關嗎,它做了什麼?
我們還是來看看原始碼吧,看Thread的構造方法到底做了什麼,各構造過載方法都呼叫了init方法,而這段程式碼就是init方法的主要內容:
有上述程式碼可得,構造方法實現的內容無非就是繼承父執行緒的屬性,如是否是後臺執行緒,優先順序等,並生成一個執行緒名稱。僅此而已,並沒有任何與建立執行緒有關的操作。
執行緒是何時建立的?
由註釋可知,Start方法將建立一個執行緒(通過呼叫本地方法start0),然後JVM會利用新建立的本地執行緒回撥Thread物件的run方法。
JVM如何建立執行緒及回撥run方法,可參考這篇文章:Java建立執行緒的方法
不呼叫Thread物件的start()方法,而是直接呼叫run()方法會如何?
那結果就是沒有建立執行緒,而是在原呼叫執行緒執行run方法。
示例程式碼:
public class ThreadRunTest { public static void main(String[] args) { Runnable runnable = new Runnable() { @Override public void run() { try { TimeUnit.SECONDS.sleep(3); //延遲列印 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Task Completed"); } }; Thread t = new Thread(runnable); t.run(); System.out.println("Main Thread print"); //如果t.run()是另外一個執行緒執行的話,此字串將先被輸出 } }
程式輸出:
此段程式碼中,run方法執行的執行緒仍然是Main主執行緒。與下述程式碼基本等價:
public class ThreadRunTest { public static void main(String[] args) { //begin try { TimeUnit.SECONDS.sleep(3); //延遲列印 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Task Completed"); //end System.out.println("Main Thread print"); //如果t.run()是另外一個執行緒的話,此字串將先被輸出 } }
值得一提的是,Runable並沒有多麼神祕,它不過是一個很普通的介面,有一個run()方法,裡面只是要執行的程式碼塊。僅此而已。它的使用方式就是,把要執行的程式碼塊寫到run方法裡面去,然後找一個執行緒去執行這個方法,就這樣。