<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>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                ## 05 看若兄弟,實如父子—Thread和Runnable詳解 > 我們有力的道德就是通過奮斗取得物質上的成功;這種道德既適用于國家,也適用于個人。 > ——羅素 上篇文章,我們學習了Java中實現多線程的兩種基本方式:繼承Thread類和實現Runnable接口。從實現的編程手法來看,認為這是兩種實現方式并無不妥。但是究其實現根源,這么講其實并不準確。在本篇文章中,我們將撤底搞懂這兩種實現方式。 相信大家之前已經對多線程的實現方式爛熟于心:繼承Thread和實現Runnable接口,這么聽起來好像兩種實現方式是并列關系,就像文章標題所講的–“看若兄弟”。但其實多線程從根本上講只有一種實現方式,就是實例化Thread,并且提供其執行的run方法。無論你是通過繼承thread還是實現runnable接口,最終都是重寫或者實現了run方法。而你真正啟動線程都是通過實例化Thread,調用其start方法。我們看下前文中不同實現方式的例子: 1、繼承thread方式 ~~~java Student xiaoming = new Student("小明",punishment); xiaoming.start(); ~~~ 2、實現runnable方式 ~~~java Thread xiaoming = new Thread(new Student("小明",punishment),"小明"); xiaoming.start(); ~~~ 第一種方式中,Student繼承了Thread類,啟動時調用的start方法,其實還是他父類Thread的start方法。并最終觸發執行Student重寫的run方法。 第二種方式中,Student實現Runnable接口,作為參數傳遞給Thread構造函數。接下來還是調用了Thread的start方法。最后則會觸發傳入的runnable實現的run方法。 兩種方式都是創建 Thread 或者 Thread 的子類,通過 Thread 的 start 方法啟動。唯一不同是第一種 run 方法實現在 Thread 子類中。第二種則是把run方法邏輯轉移到 Runnable 的實現類中。線程啟動后,第一種方式是 thread 對象運行自己的 run 方法邏輯,第二種方式則是調用 Runnable 實現的 run 方法邏輯。如下圖所示: ![圖片描述](https://img.mukewang.com/5d75ba2f00013f4a10620619.jpg)相比較來說,第二種方式是更好的實踐,原因如下: 1. java語言中只能單繼承,通過實現接口的方式,可以讓實現類去繼承其它類。而直接繼承thread就不能再繼承其它類了; 2. 線程控制邏輯在Thread類中,業務運行邏輯在Runnable實現類中。解耦更為徹底; 3. 實現Runnable的實例,可以被多個線程共享并執行。而實現thread是做不到這一點的。 看到這里,你是不是很好奇,為什么程序中調用的是Thread的start方法,而不是run方法?為什么線程在調用start方法后會執行run方法的邏輯呢?接下來我們通過開始start方法的源代碼來找到答案。 ## Thread start方法源代碼分析 我們先看Thread類start方法源代碼,如下: ~~~java 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) { } } } ~~~ 這段代碼足夠簡單,簡單到沒什么內容。主要邏輯如下: 1. 檢查線程的狀態,是否可以啟動; 2. 把線程加入到線程group中; 3. 調用了start0()方法。 可以看到Start方法中最終調用的是start0方法,并不是run方法。那么我們再看start0方法源代碼: ~~~java private native void start0(); ~~~ 什么也沒有,因為start0是一個native方法,也稱為JNI(Java Native Interface)方法。JNI方法是java和其它語言交互的方式。同樣也是java代碼和虛擬機交互的方式,虛擬機就是由C++和匯編所編寫。 由于start0是一個native方法,所以后面的執行會進入到JVM中。那么run方法到底是何時被調用的呢?這里似乎找不到答案了。 難道我們錯過了什么?回過頭來我們再看看Start方法的注解。其實讀源代碼的時候,要先讀注解,否則直接進入代碼邏輯,容易陷進去,出不來。原來答案就在start方法的注解里,我們可以看到: ~~~java * Causes this thread to begin execution; the Java Virtual Machine * calls the <code>run</code> method of this thread. * <p> * The result is that two threads are running concurrently: the * current thread (which returns from the call to the * <code>start</code> method) and the other thread (which executes its * <code>run</code> method). * <p> * It is never legal to start a thread more than once. * In particular, a thread may not be restarted once it has completed * execution. ~~~ 最關鍵一句\*the Java Virtual Machine calls the run method of this thread。\*由此我們可以推斷出整個執行流程如下: ![圖片描述](https://img.mukewang.com/5d723a8000013d9e08160179.jpg)start方法調用了start0方法,start0方法在JVM中,start0中的邏輯會調用run方法。 至此,我們已經分析清楚從線程創建到run方法被執行的邏輯。但是通過實現Runnbale的方式實現多線程時,Runnable的run方法是如何被調用的呢? ## Thread Run方法分析 對于上面提出的問題,我們先從Thread的構造函數入手。原因是Runnable的實現對象通過構造函數傳入Thread。 ~~~java public Thread(Runnable target) { init(null, target, "Thread-" + nextThreadNum(), 0); } ~~~ 可以看到Runnable實現作為target對象傳遞進來。再次調用了init方法,init 方法有多個重載,最終調用的是如下方法: ~~~java private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc, boolean inheritThreadLocals) ~~~ 此方法里有一行代碼: ~~~java this.target = target; ~~~ 原來target是Thread的成員變量: ~~~java /* What will be run. */ private Runnable target; ~~~ 此時,Thread的target被設置為你實現業務邏輯的Runnable實現。 我們再看下run方法的代碼: ~~~java @Override public void run() { if (target != null) { target.run(); } } ~~~ 看到這里是不是已經很清楚了,當你傳入了target,則會執行target的run方法。也就是執行你實現業務邏輯的方法。整體執行流程如下: ![圖片描述](https://img.mukewang.com/5d723aaa000165ab10320374.jpg)如果你是通過繼承Thread,重寫run方法的方式實現多線程。那么在第三步執行的就是你重寫的run方法。 我們回過頭看看Thread類的定義: ~~~java public class Thread implements Runnable ~~~ 原來Thread也實現了Runnable接口。怪不得Thread類的run方法上有@Override注解。所以繼承thread類實現多線程,其實也相當于是實現runnable接口的run方法。只不過此時,不需要再傳入一個Thread類去啟動。它自己已具備了thread的功能,自己就可以運轉起來。既然Thread類也實現了Runnable接口,那么thread子類對象是不是也可以傳入另外的thread對象,讓其執行自己的run方法呢?答案是可行的,你可以親手試一下。 ## 總結 至此,我們已經從理論到代碼,把多線程的兩種實現方式做了分析。在學習多線程的同時,我們也應該學習源代碼中優秀的設計模式。Java中多線程的實現采用了模版模式。Thread是模版對象,負責線程相關的邏輯,比如線程的創建、運行以及各種操作。而線程真正的業務邏輯則被剝離出來,交由Runnable的實現類去實現。線程操作和業務邏輯完全解耦,普通開發者只需要聚焦在業務邏輯實現。 執行業務邏輯,是Thread對象的生命周期中的重要一環。這一步通過調用傳入Runnable的run方法實現。thread線程整體邏輯就是一個模版,把其中一個步驟剝離出來由其他類實現,這就是模版方法模式。講到這里,我們回到標題–“實如父子”。沒錯,其實線程自身的邏輯都在thread類中,而runnable實現類只是線程執行流程中的一小步而已。所以Thread和Runnable更像是父子關系。 講到最后,拋出一個問題,你還記得start方法中如下兩行代碼嗎? ~~~java if (threadStatus != 0) throw new IllegalThreadStateException(); ~~~ 這段代碼判斷了線程狀態屬性threadStatus的值。如果不是0,則直接拋出異常,不會向下執行start0方法。那么Thread有幾種狀態,幾種狀態之間是如何轉換的呢?start之后,run方法立即就會被調用嗎?在下一篇專欄中,將會一一為你解答。
                  <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>

                              哎呀哎呀视频在线观看