<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                ## 導語 我們知道,new一個thread,調用它的start的方法,就可以創建一個線程,并且啟動該線程,然后執行該線程需要執行的業務邏輯, 那么run方法是怎么被執行的呢? ## os線程 java的一個線程實際上是對應了操作系統的一個線程;而操作系統實現線程有三種方式: * 內核線程實現 * 用戶線程實現 * 用戶線程加輕量級進程混合實現 **內核線程實現** ![](https://box.kancloud.cn/0b84d41c885289c716c737cee98f8fc4_596x517.png) **簡要說明**: 內核線程(Kernel-Level Thread簡稱KLT)是直接由操作系統內核直接支持的線程,這種線程由內核完成線程切換,內核通過操縱調度器對線程進行調度, 并負責將線程的任務映射到各個處理器上。 每個內核線程可以視為內核的一個分身,這樣操作系統就有能力處理多件事情,這種支持多線程的內核就叫做多線程內核; 程序一般不會直接操作內核線程,而是去使用內核線程的一種高級接口:輕量級進程(Light Weight Process,簡稱LWP),輕量級進程就是我們通常所講的 線程,每個輕量級進程都由一個內核線程支持,這種輕量級進程與內核線程1:1的關系稱為一對一的線程模型。 **優勢**: 由于有了內核線程的支持,每個輕量級進程都稱為一個獨立的調度單元,即使有一個輕量級進程在系統中阻塞了,也不會影響整個進程繼續工作; **劣勢**: 由于基于內核線程實現,所以各種線程操作(創建,析構及同步等)都需要進行系統調用(系統調用代價相對較高,需要在用戶態`[User Mode]`和內核態`[Kernel Mode]`來回切換); 每個輕量級進程需要一個內核線程支持,因此需要消耗一定的內核資源(如內核線程的棧空間),因此一個系統支持輕量級進程的數量是有限的; **用戶線程實現** ![](https://box.kancloud.cn/f947e2cd55a614b08b3753df0606d1c9_594x330.png) **簡要說明**: **用戶線程**: * 廣義上來講,任何非內核線程都可以認為是用戶線程(User Thread,簡稱UT); * 狹義上來講,完全建立在用戶空間的線程庫上,系統內核不能感知線程存在的實現; **特點**: * 用戶線程的創建、同步、銷毀和調度完全在用戶態中完成,不需要內核的幫助,這種線程不需要切換到內核態,操作可以非常快速且低消耗; * 支持更大的線程數量; * 這種進程與用戶線程之間1:N的關系稱為一對多的線程模型; * 用戶線程的優勢就是不需要系統內核支援,劣勢就是沒有內核支持,所有的線程操作(如線程的創建、切換和調度等)都需要用戶程序自己處理。 **用戶線程加輕量級進程混合實現** ![](https://box.kancloud.cn/a26c040a94071b246b842f1964dff5d2_593x449.png) **簡要說明**: **用戶線程+輕量級進程特點**: * 用戶線程的創建、析構、切換等操作很廉價; * 支持大規模的用戶線程并發; * 操作系統提供的輕量級進程作為用戶線程和內核線程之間的橋梁,提供線程調度功能及處理器映射; * 用戶線程的系統調用通過輕量級進程完成,降低了整個進程完全被阻塞的風險; * 這種用戶線程和輕量級進程的數量比不定,即N:M的關系,稱為多對多的線程模型 ## Java線程 Java線程在JDK1.2之前,是基于用戶線程實現的。而在JDK1.2中,線程模型替換為基于操作系統原生線程模型來實現。 而在目前的JDK版本中,操作系統支持怎樣的線程模型,在很大程度上決定了Java虛擬機的線程是怎樣映射的,這點在不同的平臺上沒法達成一致。 對于Sun JDK來說,它的Windows版本和Linux版本都是使用一對一的線程模型實現的,一條Java線程映射到一條輕量級進程之中。 ### Java線程創建 **創建方式** ~~~ public class TestThread { class ThreadExtend extends Thread { @Override public void run() { // TODO: 2018/9/6 } } class RunnableExtend implements Runnable { @Override public void run() { // TODO: 2018/9/6 } } private void testThreadPortal() { Thread thread1 = new ThreadExtend(); thread1.start(); Thread thread2 = new Thread(new RunnableExtend()); thread2.start(); } } ~~~ **Desc**:我們看到,無論以哪種方式創建,最終我們都會重寫一個叫做 run 的方法,來處理我們的業務邏輯,然而我們都是調用一個start方法,來啟動一個線程; 那 start方法和run方法之間是一個什么關系呢?從后邊的介紹我們將獲得這樣一個信息:run就是一個回調函數,和我們普通的函數沒有區別。 **Java線程的實現** 一個 Java 線程的創建本質上就對應了一個本地線程(native thread)的創建,兩者是一一對應的。 關鍵問題是:本地線程執行的應該是本地代碼,而 Java 線程提供的線程函數(run)是 Java 方法,編譯出的是 Java 字節碼, 所以, Java 線程其實提供了一個統一的線程函數,該線程函數通過 Java 虛擬機調用 Java 線程方法 , 這是通過 Java 本地方法調用來實現的。 以下是 Thread#start 方法的示例: ~~~ public synchronized void start() { /** * This method is not invoked for the main method thread or "system" * group threads created/set up by the VM. Any new functionality added * to this method in the future may have to also be added to the VM. * * A zero status value corresponds to state "NEW". */ if (threadStatus != 0) throw new IllegalThreadStateException(); /* Notify the group that this thread is about to be started * so that it can be added to the group's list of threads * and the group's unstarted count can be decremented. */ 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 */ } } } ~~~ 可以看到它實際上調用了本地方法 start0, 而start0聲明如下: `private native void start0();` 也就是新創建的線程啟動調用native start0方法,而這些native方法的注冊是在Thread對象初始化的時候完成的,look: ~~~ public class Thread implements Runnable { /* Make sure registerNatives is the first thing <clinit> does. */ private static native void registerNatives(); static { registerNatives(); } //...... } ~~~ Thread 類有個 registerNatives 本地方法,該方法主要的作用就是注冊一些本地方法供 Thread 類使用,如 start0(),stop0() 等等,可以說,所有操作本地線程的本地方法都是由它注冊的。 這個方法放在一個 static 語句塊中,當該類被加載到 JVM 中的時候,它就會被調用,進而注冊相應的本地方法。 而本地方法 registerNatives 是定義在 Thread.c 文件中的。Thread.c 是個很小的文件,它定義了各個操作系統平臺都要用到的關于線程的公用數據和操作,如下: ~~~ JNIEXPORT void JNICALL Java_Java_lang_Thread_registerNatives (JNIEnv *env, jclass cls){ //registerNatives (*env)->RegisterNatives(env, cls, methods, ARRAY_LENGTH(methods)); } static JNINativeMethod methods[] = { {"start0", "()V",(void *)&JVM_StartThread}, //start0 方法 {"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->start0 的方法,實際上會調用到 JVM_StartThread 方法,那這個方法又是怎么處理的呢? 實際上,我們需要看到的是該方法最終要調用 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(), //LOOK! 看這里 vmSymbolHandles::void_method_signature(),THREAD); } ~~~ 可以看到調用了 vmSymbolHandles::run_method_name 方法,而run_method_name是在 vmSymbols.hpp 用宏定義的: ~~~ class vmSymbolHandles: AllStatic { ... template(run_method_name,"run") //LOOK!!! 這里決定了調用的方法名稱是 “run”! ... } ~~~ ## Java線程創建調用關系 ![](https://box.kancloud.cn/c61e2b56da97bf0cc8fd5168e468e1ab_604x352.png)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看