妹子問我為啥啟動線程時使用 Start 而不是 Run
本文轉載自微信公眾號「Java極客技術」,作者鴨血粉絲。轉載本文請聯系Java極客技術公眾號。
今天團隊里面的妹子問阿粉,為什么在啟動線程的時候,都使用 start 方法,而不是 run 方法呢
還好阿粉平時一直有在學習,要不真的被妹子問住了
在多線程中,如果想讓一個線程啟動,你使用的方法一定是 thread.start() 方法,而不是 thread.run() 方法(啥,你用的不是 thread.start() 方法?乖,你的打開方式不對哦,下次不要這樣了
有沒有疑惑,為什么每次我們都習慣調用 start() 方法,為什么不直接調用 run() 方法來啟動線程呢?
而且如果去看源碼的話,你會發現,在 thread.start() 方法中,其實最后還是調用了 thread.run() 方法來執行
- Causes this thread to begin execution; the Java Virtual Machine
- calls the <code>run</code> method of this thread.
上面的注釋翻譯一下:當線程開始執行時, JVM 會調用此線程的 run 方法
也就是說,線程的 run 方法是由 JVM 直接調用的,在 Java 中如果我們想要直接調用 run 方法也是可以的,因為在 Java 中 run 方法是 public 的
- @Override
- public void run() {
- if (target != null) {
- target.run();
- }
- }
那既然 start 方法最后調用的也是 run 方法,再加上 run 方法本身支持直接調用,那為啥我們平時寫的程序都是調用 start 方法,而不是 run 方法呢
那是因為,如果直接調用 run 方法,就不是多線程了
為了方便解釋,咱們看個小 demo :
- public class RunThread {
- public static void main(String[] args) {
- Thread runThread = new Thread(new Runnable() {
- @Override
- public void run() {
- System.out.printf("Run begin another , 當前線程 : %s.%n" ,Thread.currentThread().getName());
- }
- });
- // 啟動線程
- runThread.start();
- // 直接調用 run 方法 -- 演示使用,實際中不要這么做!
- runThread.run();
- System.out.printf("Run begin , 當前線程 : %s.%n" ,Thread.currentThread().getName());
- }
- }
上面的程序運行結果如下:
你會發現, runThread 的 run 方法被執行了兩次
一次是 run 方法運行在自己的線程中,從 Run begin another , 當前線程 : Thread-0 可以看到,這個線程是運行在 Thread-0 中
另外一次是因為我們的程序代碼直接調用了 run 方法,此時的線程運行在 main 線程中,從 Run begin another , 當前線程 : main 可以看出來
也就是說,如果我們直接調用 run 方法的話,線程并不是運行在自己的線程中,而是運行在了當前線程中
我們為什么要創建多線程?不就是希望多個線程并行執行,比如現在我是線程 A ,此時又起了一個線程,那么我希望這個線程是和線程 A 一起運行的,如果直接調用了 run 方法的話,就運行在線程 A 里面來了
并沒有達到創建多線程的目標,這怎么行呢,對不對
所以在啟動線程時,都是使用 start 方法,而不是 run 方法
這一點,其實在源碼中也有說明:
the Java Virtual Machine calls the run method of this thread.
The result is that two threads are running concurrently:
the current thread (which returns from the call to the start method)
and the other thread (which executes its run method).
在 JVM 調用線程的 run 方法之后,結果就是兩個線程同時運行:
- 當前線程(從調用返回到 start 方法)
- 另一個線程(執行 run 方法)
一個線程能不能 start 兩次?
妹子搞懂了為什么線程一般都使用 start 方法,不使用 run 方法,因為調用的話,就違背了我們想要用多線程去處理的初衷
妹子又問阿粉,那一個線程是不是可以 start 兩次呢?
負責任的阿粉趕緊告訴小妹妹是不可以的
如果一個線程啟動兩次,想都不用想會拋出 IllegalThreadStateException 這個異常
這個錯誤我們也能在源碼中看到:
- if (threadStatus != 0)
- throw new IllegalThreadStateException();
線程開始 start 時,會首先判斷 threadStatus 的值是否為 0 ,如果值不是 0 的話,說明這個線程的 state 狀態不是 new 就拋出 IllegalThreadStateException 異常
啊?竟然還想問阿粉,線程的狀態除了 new 還有什么?阿粉以前寫過一篇,要不要看看:面試官沒想到,一個 Java 線程生命周期,我可以扯半小時