[不懂就問]. 為啥使用Thread類創建線程start以后可以直接run呢

舉個栗子:http://www.lxweimin.com/p/79f5e0bcd652
線程調用start()方法后便會run()起來,但是為什么呢,加個斷點debug一下來看看.

  • 首先執行Thread.start()方法,來看源碼:
public synchronized void start() {
     
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
        group.add(this);

        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                
            }
        }
    }
  • 方法首先判斷threadStatus變量值,來看這個變量的聲明
private volatile int threadStatus = 0;
//volatile是一個類型修飾符(type specifier).volatile的作用是作為指令[關鍵字],確保本條指令不會因[編譯器]的優化而省略,且要求每次直接讀值。

看名字應該是表示線程狀態的一個狀態,默認為0.非零的話拋出一個非法線程狀態的異常.

  • 然后向ThreadGroup的group添加當前線程對象.
  • 定義一個Boolean變量started標記
  • 然后執行start0方法,執行完以后控制臺就已經有輸出了
    看來關鍵就是這個start0方法
    來看是聲明
private native void start0();

(以下過程比較復雜,像我這樣的初學者可以直接拖到問尾大致了解一下)
(以下部分涉及轉載,原文地址:https://www.ibm.com/developerworks/cn/java/j-lo-processthread/#icomments
)

  • Thread 類有個 registerNatives 本地方法,該方法主要的作用就是注冊一些本地方法供 Thread 類使用,如 start0(),stop0() 等等,可以說,所有操作本地線程的本地方法都是由它注冊的 . 這個方法放在一個 static 語句塊中,這就表明,當該類被加載到 JVM 中的時候,它就會被調用,進而注冊相應的本地方法。
private static native void registerNatives(); 
 static{ 
      registerNatives(); 
 }
  • 本地方法 registerNatives 是定義在 Thread.c 文件中的。Thread.c 是個很小的文件,定義了各個操作系統平臺都要用到的關于線程的公用數據和操作.
JNIEXPORT void JNICALL 
Java_Java_lang_Thread_registerNatives (JNIEnv *env, jclass cls){ 
  (*env)->RegisterNatives(env, cls, methods, ARRAY_LENGTH(methods)); 
} 
static JNINativeMethod methods[] = { 
   {"start0", "()V",(void *)&JVM_StartThread}, 
   {"stop0", "(" OBJ ")V", (void *)&JVM_StopThread}, 
    {"isAlive","()Z",(void *)&JVM_IsThreadAlive}, 
    {"suspend0","()V",(void *)&JVM_SuspendThread}, 
    {"resume0","()V",(void *)&JVM_ResumeThread}, 
    {"setPriority0","(I)V",(void *)&JVM_SetThreadPriority}, 
    {"yield", "()V",(void *)&JVM_Yield}, 
    {"sleep","(J)V",(void *)&JVM_Sleep}, 
    {"currentThread","()" THD,(void *)&JVM_CurrentThread}, 
    {"countStackFrames","()I",(void *)&JVM_CountStackFrames}, 
    {"interrupt0","()V",(void *)&JVM_Interrupt}, 
    {"isInterrupted","(Z)Z",(void *)&JVM_IsInterrupted}, 
    {"holdsLock","(" OBJ ")Z",(void *)&JVM_HoldsLock}, 
    {"getThreads","()[" THD,(void *)&JVM_GetAllThreads}, 
    {"dumpThreads","([" THD ")[[" STE, (void *)&JVM_DumpThreads}, 
};
  • 到此,可以容易的看出 Java 線程調用 start 的方法,實際上會調用到 JVM_StartThread 方法,那這個方法又是怎樣的邏輯呢。實際上,我們需要的是(或者說 Java 表現行為)該方法最終要調用 Java 線程的 run 方法,事實的確如此。 在 jvm.cpp 中,有如下代碼段:
JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread)) 
   …
    native_thread = new JavaThread(&thread_entry, sz); 
   …
  • 這里JVM_ENTRY是一個宏,用來定義JVM_StartThread 函數,可以看到函數內創建了真正的平臺相關的本地線程,其線程函數是 thread_entry.
static void thread_entry(JavaThread* thread, TRAPS) { 
   HandleMark hm(THREAD); 
    Handle obj(THREAD, thread->threadObj()); 
    JavaValue result(T_VOID); 
    JavaCalls::call_virtual(&result,obj, 
    KlassHandle(THREAD,SystemDictionary::Thread_klass()), 
    vmSymbolHandles::run_method_name(), 
vmSymbolHandles::void_method_signature(),THREAD); 
}
  • 可以看到調用了 vmSymbolHandles::run_method_name 方法,這是在 vmSymbols.hpp 用宏定義的:
class vmSymbolHandles: AllStatic { 
   …
    template(run_method_name,"run") 
   …
}
  • 至于 run_method_name 是如何聲明定義的,因為涉及到很繁瑣的代碼細節,本文不做贅述。感興趣的讀者可以自行查看 JVM 的源代碼。


    圖一
  • 綜上所述,Java 線程的創建調用過程如 圖 1 所示,首先 , Java 線程的 start 方法會創建一個本地線程(通過調用 JVM_StartThread),該線程的線程函數是定義在 jvm.cpp 中的 thread_entry,由其再進一步調用 run 方法。可以看到 Java 線程的 run 方法和普通方法其實沒有本質區別,直接調用 run 方法不會報錯,但是卻是在當前線程執行,而不會創建一個新的線程。

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 寫在前面 寫作時間:2017.5本文JDK版本:JDK 1.8本文簡述:從Java的新建一個線程開始,溯源到Thr...
    Van96閱讀 3,493評論 9 17
  • 一:java概述:1,JDK:Java Development Kit,java的開發和運行環境,java的開發工...
    ZaneInTheSun閱讀 2,687評論 0 11
  • Java多線程學習 [-] 一擴展javalangThread類 二實現javalangRunnable接口 三T...
    影馳閱讀 2,986評論 1 18
  • 本文主要講了java中多線程的使用方法、線程同步、線程數據傳遞、線程狀態及相應的一些線程函數用法、概述等。 首先講...
    李欣陽閱讀 2,492評論 1 15
  • 作為全職媽媽,靠寫稿子賺錢,難上加難,不是接稿子很難,而是好多稿子都是限制時間交稿,自己沒有固定的時間是不敢接稿子...
    阿布阿布嘛閱讀 421評論 3 2