<input id="ohw05"></input>
  • <table id="ohw05"><menu id="ohw05"></menu></table>
  • <var id="ohw05"></var>
  • <code id="ohw05"><cite id="ohw05"></cite></code>
    <label id="ohw05"></label>
    <var id="ohw05"></var>
  • 用代碼說話:如何正確啟動線程

    先來看下結論:正確啟動線程的方式是使用start()方法,而不是使用run()方法。

    代碼實戰

    1. 輸出線程名稱

    “Talk is cheap. Show me the code”,用代碼說話:分別調用run()方法和start()方法,打印輸出線程的名字。

    public class StartAndRunThread {
        public static void main(String[] args) {
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            };
            runnable.run();
            new Thread(runnable).start();
        }
    }
    

    運行結果:
    image.png

    2. 深入一點

    如果代碼是這樣的,執行結果有什么不同呢?

    public class StartAndRunThread {
        public static void main(String[] args) {
            Runnable runnable = new Runnable() {
                @Override
                public void run() {
                    System.out.println(Thread.currentThread().getName());
                }
            };
            runnable.run();
            new Thread(runnable).start();
            runnable.run();
        }
    }
    

    執行結果為:
    image.png

    是不是有點意外?然而,這就是真相。其實也不難解釋。

    1. 我們說的并發是什么,并發不就是線程之間的運行互不干擾嘛?當JVM啟動的時候,創建一個mian線程來運行main()方法。當執行到“new Thread(runnable).start();”的時候main線程會新建一個Thread-0線程。main線程和Thread-0線程的執行時互不相干的,所以可能不會出現“main-Thread-0-main”的結果。

    2. 我執行了n(n>20)次,運行結果依然如上圖所示,沒有出現“main-Thread-0-main”。這是為什么呢?回憶一下線程的生命周期, Java中,線程(Thread)定義了6種狀態: NEW(新建)、RUNNABLE(可執行)、BLOCKED(阻塞)、WAITING(等待)、TIMED_WAITING(限時等待)、TERMINATED(結束)。當調用了start()方法之后,線程進入RUNNABLE狀態,RUNNABLE的意思是可運行,即可能正在執行,也可能沒有正在執行。那調用了start方法之后,什么時候執行呢?調用start()方法之后,我們只是告訴JVM去執行這個線程,至于什么時候運行是由線程調度器來決定的。從操作系統層面,其實調用start()方法之后要去獲取操作系統的時間片,獲取到才會執行。這個問題,可以對比思考“ thread.start()調用之后線程會立刻執行嗎?”更多可以參考:從源碼解讀線程(Thread)和線程池(ThreadPoolExecutor)的狀態

    start()方法源碼分析

    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 */
            }
        }
    }
    

    可以看到,start()方法被synchronized關鍵字修飾,保證了線程安全。啟動流程分為下面三個步驟:

    1. 首先會檢查線程狀態,只有threadStatus == 0(也就是線程處于NEW狀態)狀態下的線程才能繼續,否則會拋出IllegalThreadStateException。

    2. 將線程加入線程組

    3. 調用native方法——start0()方法啟動線程。

    線程啟動相關問題

    1. 一個線程兩次調用start()方法會出現什么情況?

    會拋出IllegalThreadStateException,具體原因可以用源碼和線程啟動步驟進行說明。

    2. 既然 start() 方法會調用 run() 方法,為什么我們選擇調用 start() 方法,而不是直接調用 run() 方法呢?

    start()才是真正啟動一個線程,而如果直接調用run(),那么run()只是一個普通的方法而已,和線程的生命周期沒有任何關系。用代碼驗證一下:

    public class Main implements Runnable {
    
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName());
        }
    
        public static void main(String[] args) {
            new Main().run();
            new Thread(new Main()).start();
        }
    
    }
    

    image.png

    在上面代碼中,直接調用run()方法,run()只是一個普通的方法,由當前線程——main線程執行。start()才是真正啟動一個線程——Thread0,run()方法由線程Thread0執行。

    3. 上面說start()會調用run()方法,這個怎么證明?為什么在start()方法的源碼中沒有看到調用了run()方法?

    可以看start()方法的注釋部分:

    /**
    * 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.
    *
    * @exception  IllegalThreadStateException  if the thread was already
    *               started.
    * @see        #run()
    * @see        #stop()
    */
    

    也就是說當該線程開始執行的時候,Java虛擬機會自動調用該線程的run()方法。

    posted @ 2020-01-29 20:36  James_Shangguan  閱讀(731)  評論(0編輯  收藏  舉報
    国产美女a做受大片观看