【線程內參】啓動線程

啓動Java線程

public class StartAndRunMethod {
    public static void main(String[] args) {
        Runnable task = () -> {
            System.out.println(Thread.currentThread().getName());
        };
        task.run();
        new Thread(task).start();
    }
}

運行結果:

main
Thread-0

上面的語句無論是task.run(),還是new Thread(task).start(),都是由main線程來執行的。但Runnable對象run方法內容分別由main線程和子線程執行。

小結:調用start方法纔是真正意義上的啓動線程,經歷線程的生命週期;而run方法只是一個普通方法,直接調用不會使用子線程來運行。

start方法底層實現

調用start方法會告訴JVM在合適時候啓動線程,運行run方法。

start方法涉及到兩個線程:父線程(用於創建子線程)和子線程。啓動子線程需要做一些準備工作,例如獲取到除了CPU之外的所有資源,例如上下文、棧、線程狀態等。

// java.lang.Thread
public synchronized void start() {
    // 0狀態對應線程的NEW狀態
    if (threadStatus != 0)
        throw new IllegalThreadStateException();
    // 通知線程組當前線程將要啓動:當前線程新增到線程組的線程列表,未啓動線程數減1    
    group.add(this);

    boolean started = false;
    try {
        start0();
        started = true;
    } finally {
        try {
            if (!started) {
                group.threadStartFailed(this);
            }
        } catch (Throwable ignore) {
            /* do nothing. If start0 threw a Throwable then it will be passed up the call stack */
        }
    }
}

// JNI方法
private native void start0();

start方法的執行流程

  1. 檢查線程狀態,只有NEW狀態才能繼續,否則拋出IllegalThreadStateException(非法線程狀態異常);
  2. 當前線程加入線程組
  3. 調用Java本地方法start0()啓動線程。

注意點:

  • start方法由synchronized修飾,是線程安全的。
  • 由JVM創建的main方法線程和system組線程,不會通過start方法啓動。
  • 線程終止(Terminated)後,不允許再回到Runnable狀態。

run方法底層實現

如果當前線程是通過實現Runnable接口方式創建,會調用Runnable對象的run方法;否則不做任何事情。如果通過繼承Thread方式創建線程,需要重寫run方法。

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

示例:代碼同時使用兩種方式
匿名內部類實現Runnable接口,並在類內部重寫run方法。重寫run方法的代碼直接覆蓋Thread類run方法代碼,Runnable中run方法實現代碼不會執行。

Thread thread = new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("使用Runnable方式創建線程");
    }
}) {
    @Override
    public void run() {
        System.out.println("使用Thread方式創建線程");
    }
};
thread.start();
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章