為什么啟動線程是start方法?


為什么啟動線程是start方法

 

十年可見春去秋來,百年可證生老病死,千年可嘆王朝更替,萬年可見斗轉星移。

             凡人如果用一天的視野,去窺探百萬年的天地,是否就如同井底之蛙?

 

背景:啟動線程是start() 還是run() 方法?相信這個問題很多人都知道是start(),但是如果我再問下去呢,為什么是start()?你會如何作答呢?

 

一、理論課

當用start()開始一個線程后,線程就進入就緒狀態,使線程所代表的虛擬處理機處於可運行狀態,這意味着它可以由JVM調度並執行;但是這並不意味着線程就會立即運行,只有當cpu分配時間片時,這個線程獲得時間片時,才開始執行run()方法;start()方法去調用run(),而run()方法則是需要去重寫的,其包含的是線程的主體(真正的邏輯)。

二、線程六大狀態

Java 中,定義了 6 種線程狀態,NEWRUNNABLEBLOCKEDWAITINGTIMED_WAITING和TERMINATED

1 public enum State{ 2  NEW, 3  RUNNABLE, 4  BLOCKED, 5  WAITING, 6  TIMED_WAITING, 7  TERMINATED; 8 }

6 種線程狀態關系圖

 

三、代碼層次

楊總說的,一切問題歸咎於源碼!

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() 是啟動多線程的關鍵
             * 執行完成之后,新的線程已經在運行了
             * 這里會創建一個新的線程,是一個 native 方法
             */
            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 */
            }
        }
    }

 run方法源碼:

 @Override
    public void run() {
     // 簡單的運行,不會新起線程,target 是 Runnable
        if (target != null) {
            target.run();
        }
    }

從start()和run()方法的源碼可以看出,start方法的源碼也沒幾行代碼,最主要的是 start0() 方法;run() 方法的源碼也比較簡單的,就是一個普通方法的調用;重點是這個 start0() 方法,她是真正實現多線程的關鍵。

start0方法源碼:

// native :就是本地方法 
private native void start0(); 

關於native方法簡述:

1、被native關鍵字修飾的方法叫做本地方法,本地方法和其它方法不一樣,本地方法意味着和平台有關,因此使用了native的程序可移植性都不太高;

2、native方法在JVM中運行時數據區也和其它方法不一樣,它有專門的本地方法棧;

3、native方法主要用於加載文件和動態鏈接庫,由於Java語言無法訪問操作系統底層信息(比如:底層硬件設備等),這時候就需要借助C語言來完成了;

4、被native修飾的方法可以被C語言重寫。

Java 跨平台圖

 

在start()中start0 被標記成 native ,也就是本地方法,並不需要我們去實現或者了解,只要了解下為什么 start0() 會標記成 native ?

如上圖,start() 方法調用 start0() 方法后,該線程並不一定會立馬執行,只是將線程變成了可運行狀態(NEW ---> RUNNABLE);具體什么時候執行,取決於 CPU ,由 CPU 統一調度;我們又知道 Java 是跨平台的,可以在不同系統上運行,每個系統的 CPU 調度算法不一樣,所以就需要做不同的處理,這件事情就只能交給 JVM 來實現了,start0() 方法自然就表標記成了 native。

 四、總結

Java 中實現真正的多線程是 start 中的 start0() 方法,run() 方法只是一個包含業務邏輯普通的方法;start是啟動多線程的唯一方式,其使得線程由創建態到就緒態,而這個線程是否被運行是由系統調度所決定的。

 

  十年可見春去秋來

    百年可證生老病死

      千年可嘆王朝更替

        萬年可見斗轉星移

          凡人如果用一天的視野

               去窺探百萬年的天地

                  是否就如同井底之蛙?

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM