Java Thread中的start() 和 run()方法對比

start() 和 run()

start()

  • 調用start方法,只是通知 jvm有一個線程要啓動,讓其在有空的時候啓動線程,至於何時啓動線程並不是start能決定的,最終啓動線程的時間點是由線程調度器決定的。所以線程啓動的順序並不是由調用start方法的順序決定的,這也說明了爲什麼有時候後調用start方法的線程會先啓動。(start只負責通知 jvm啓動,具體什麼時候啓動由線程調度器說了算
  • 調用start方法,涉及兩個線程,一個是主線程,即調用start方法的線程,另一個是要啓動的線程(新創建的線程)。
  • start方法的執行流程
    • (1)檢查線程狀態,只有在new狀態下的線程才能繼續,否則拋出IllegalThreadStateException(在運行中或者已經結束的線程,都不能再次啓動);
    • (2)被加入線程組;
    • (3)調用 start0() 方法啓動線程;

注意:
(1)start方法是被synchronized修飾的方法,可以保證線程安全。
(2)由 jvm 創建的main方法線程和system組線程,並不會通過start來啓動。

Thread.java 中start方法的源碼如下:

public synchronized void start() {
    // 如果線程不是"新建狀態(new)",則拋出異常!
    if (threadStatus != 0)
        throw new IllegalThreadStateException();

    // 將線程添加到ThreadGroup中
    group.add(this);
    
    boolean started = false;
    try {
        // 通過start0()啓動線程
        start0();
        // 設置started標記
        started = true;
    } finally {
        try {
            if (!started) {
                group.threadStartFailed(this);
            }
        } catch (Throwable ignore) {
        }
    }
}

start()實際上是通過本地方法start0()啓動線程的。而start0()會新運行一個線程,新線程會調用run()方法。

private native void start0();

run()

如果直接調用 run() ,那麼 run() 只是一個普通的方法而已,和線程的生命週期無關,程序中依然只有主線程這一個線程,其程序執行路徑還是隻有一條,還是要順序執行,還是要等待run方法體執行完畢後纔可繼續執行下面的代碼,這些就沒有達到實現多線程的目的。

Thread.java中run的源碼如下:

public void run() {
    if (target != null) {
        target.run();
    }
}

target是一個Runnable接口的實現類的對象。run()就是直接調用Thread線程的Runnable實現類對象的run()方法,並不會新建一個線程。

兩者區別及總結

  • start() : 用start方法來啓動線程,真正實現了多線程運行,其無需等待run方法體代碼執行完畢而直接繼續執行下面的代碼。通過調用Thread類的start()方法來啓動一個線程,這時此線程處於就緒(可運行)狀態並沒有運行,一旦得到cpu時間片,就開始執行run()方法,這裏方法 run()稱爲線程體,它包含了要執行的這個線程的內容,run方法運行結束,此線程隨即終止;
  • run():run()方法只是類的一個普通方法而已,如果直接調用Run方法,程序中依然只有主線程這一個線程,其程序執行路徑還是隻有一條,還是要順序執行還是要等待run方法體執行完畢後纔可繼續執行下面的代碼,這樣就沒有達到寫線程的目的。

start() 纔是真正啓動一個線程的方法,啓動線程不能直接調用run方法,應該調用start方法,來間接地調用run方法啓動線程。

/**
 * 對比start和run方法兩種方式啓動線程
 */
public class StartAndRunMethod {
   public static void main(String[] args) {
      //使用lambdab表達式創建Runnable接口實現類的實例
      Runnable runnable = ()->{
         System.out.println(Thread.currentThread().getName());
      };
      /*
      直接調用run方法,那麼這時run方法只是一個普通的方法而已,
      程序中依然只有主線程一個線程,所以這裏執行的是主線程(main)
       */
      runnable.run();//這樣並不是執行新建的線程,這裏執行的是主線程(main)

      /*
      調用start可能並不會立馬啓動線程,start只是告訴jvm有一個線程要啓動,
      讓其有空的時候啓動。
      最終決定線程的啓動時間點是由線程調度器決定。
       */
      new Thread(runnable).start();
   }
}

運行結果:

main
Thread-0

參考:
Java Thread 的 run() 與 start() 的區別
Java多線程系列–“基礎篇”03之 Thread中start()和run()的區別

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章