深入淺出線程Thread類的start()方法和run()方法

一、初識

java的線程是通過java.lang.Thread類來實現(xiàn)的。VM啟動時會有一個由主方法所定義的線程??梢酝ㄟ^創(chuàng)建Thread的實例來創(chuàng)建新的線程。每個線程都是通過某個特定Thread對象所對應的方法run()來完成其操作的,方法run()稱為線程體。通過調(diào)用Thread類的start()方法來啟動一個線程。

在Java當中,線程通常都有五種狀態(tài),創(chuàng)建、就緒、運行、阻塞和死亡。

第一是創(chuàng)建狀態(tài)。在生成線程對象,并沒有調(diào)用該對象的start方法,這是線程處于創(chuàng)建狀態(tài)。

第二是就緒狀態(tài)。當調(diào)用了線程對象的start方法之后,該線程就進入了就緒狀態(tài),但是此時線程調(diào)度程序還沒有把該線程設(shè)置為當前線程,此時處于就緒狀態(tài)。在線程運行之后,從等待或者睡眠中回來之后,也會處于就緒狀態(tài)。

第三是運行狀態(tài)。線程調(diào)度程序?qū)⑻幱诰途w狀態(tài)的線程設(shè)置為當前線程,此時線程就進入了運行狀態(tài),開始運行run函數(shù)當中的代碼。

第四是阻塞狀態(tài)。線程正在運行的時候,被暫停,通常是為了等待某個時間的發(fā)生(比如說某項資源就緒)之后再繼續(xù)運行。sleep,suspend,wait等方法都可以導致線程阻塞。

第五是死亡狀態(tài)。如果一個線程的run方法執(zhí)行結(jié)束或者調(diào)用stop方法后,該線程就會死亡。對于已經(jīng)死亡的線程,無法再使用start方法令其進入就緒。

二、start()方法

1、為什么需要start方法;它的作用是什么?

start()方法來啟動線程,真正實現(xiàn)了多線程運行。
start方法的作用就是將線程由NEW狀態(tài),變?yōu)镽UNABLE狀態(tài)。當線程創(chuàng)建成功時,線程處于NEW(新建)狀態(tài),如果你不調(diào)用start( )方法,那么線程永遠處于NEW狀態(tài)。調(diào)用start( )后,才會變?yōu)镽UNABLE狀態(tài),線程才可以運行。

2、調(diào)用start()方法后,線程是不是馬上執(zhí)行?

線程不是馬上執(zhí)行的;準確來說,調(diào)用start( )方法后,線程的狀態(tài)是“READY(就緒)”狀態(tài),而不是“RUNNING(運行中)”狀態(tài)(關(guān)于線程的狀態(tài)詳細。線程要等待CPU調(diào)度,不同的JVM有不同的調(diào)度算法,線程何時被調(diào)度是未知的。因此,start()方法的被調(diào)用順序不能決定線程的執(zhí)行順序

注意:
由于在線程的生命周期中,線程的狀態(tài)由NEW ----> RUNABLE只會發(fā)生一次,因此,一個線程只能調(diào)用start()方法一次,多次啟動一個線程是非法的。特別是當線程已經(jīng)結(jié)束執(zhí)行后,不能再重新啟動。

三、run( )方法

1、run方法又是一個什么樣的方法?run方法與start方法有什么關(guān)聯(lián)?

run()方法當作普通方法的方式調(diào)用
run( )其實是一個普通方法,只不過當線程調(diào)用了start( )方法后,一旦線程被CPU調(diào)度,處于運行狀態(tài),那么線程才會去調(diào)用這個run()方法;

2、run()方法的執(zhí)行是不是需要線程調(diào)用start()方法

上面說了,run()方法是一個普通的對象方法,因此,不需要線程調(diào)用start()后才可以調(diào)用的??梢跃€程對象可以隨時隨地調(diào)用run方法。

#Example1:

  Thread t1 = new Thread(new MyTask(1));
  Thread t2 = new Thread(new MyTask(2));
     t1.run();
     t2.run();

上面的輸出結(jié)果是固定的:

count的值:1
count的值:2

再看另一個實例:

 Thread t1 = new Thread(new MyTask());
 Thread t2 = new Thread(new MyTask());
     t1.start();
     t2.start();

這個輸出結(jié)果不是固定的,因為線程的運行沒法預測。運行結(jié)果可能不一樣。

MyTask 類:

//實現(xiàn)Runnable接口
class MyTask implements Runnable{

    int count;
    public MyTask(int count) {
        this.count=count;
    }
    @Override
    public void run() {
        System.out.println("count的值:"+count);
    }
}

#Example2:

1、用start方法啟動線程

    public class Main {  
      
        public static void main(String[] args) {  
            Thread t1 = new Thread(new T1());  
            Thread t2 = new Thread(new T2());  
            t1.start();  
            t2.start();  
        }  
      
    }  
      
    class T1 implements Runnable {  
        public void run() {  
            try {  
                for(int i=0;i<10;i++){  
                    System.out.println(i);  
                    Thread.sleep(100);  //模擬耗時任務  
                }  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
        }  
    }  
      
    class T2 implements Runnable {  
        public void run() {  
            try {  
                for(int i=0;i>-10;i--){  
                    System.out.println(i);  
                    Thread.sleep(100);  //模擬耗時任務  
                }  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
        }  
    }  

結(jié)果:

這里寫圖片描述

說明兩線程是并發(fā)執(zhí)行的。

2、先用run方法啟動線程
將上面的start()改為run()

    public class Main {  
      
        public static void main(String[] args) {  
            Thread t1 = new Thread(new T1());  
            Thread t2 = new Thread(new T2());  
            t1.run();  
            t2.run();  
        }  
      
    }  
這里寫圖片描述

說明兩線程實際是順序執(zhí)行的。

總結(jié):

通過實例1和實例和我們可以知道start方法是用于啟動線程的,可以實現(xiàn)并發(fā),而run方法只是一個普通方法,是不能實現(xiàn)并發(fā)的,只是在并發(fā)執(zhí)行的時候會調(diào)用。

說到這,不知道小伙伴們有沒有明白這兩個方法的區(qū)別,如果還有疑問,可以留言交流。

四、start()方法和run()方法源碼解析(基于JDK1.7.0_40)

    public synchronized void start() {  
        // 如果線程不是"就緒狀態(tài)",則拋出異常!  
        if (threadStatus != 0)  
            throw new IllegalThreadStateException();  
        // 將線程添加到ThreadGroup中  
        group.add(this);  
        boolean started = false;  
        try {  
            // 通過start0()啟動線程,新線程會調(diào)用run()方法  
            start0();  
            // 設(shè)置started標記=true  
            started = true;  
        } finally {  
            try {  
                if (!started) {  
                    group.threadStartFailed(this);  
                }  
            } catch (Throwable ignore) {  
            }  
        }  
    }  
public void run() {  
    if (target != null) {  
        target.run();  
    }  
} 

五、真正理解Thread類

Thread類的對象其實也是一個java對象,只不過每一個Thread類的對象對應著一個線程。Thread類的對象就是提供給用戶用于操作線程、獲取線程的信息。真正的底層線程用戶是看不到的了。
因此,當一個線程結(jié)束了,死掉了,對應的Thread的對象仍能調(diào)用,除了start( )方法外的所有方法(死亡的線程不能再次啟動),如run( )、getName( )、getPriority()等等

//簡單起見,使用匿名內(nèi)部類的方法來創(chuàng)建線程
    Thread thread = new Thread(){
        @Override
        public void run() {
            System.out.println("Thread對象的run方法被執(zhí)行了");
        }
    };
    //線程啟動
    thread.start();
    
    //用循環(huán)去監(jiān)聽線程thread是否還活著,只有當線程thread已經(jīng)結(jié)束了,才跳出循環(huán)
    while(thread.isAlive()){}
    //線程thread結(jié)束了,但仍能調(diào)用thread對象的大部分方法
    System.out.println("線程"+thread.getName()+"的狀態(tài):"+thread.getState()+"---優(yōu)先級:"+thread.getPriority());
    //調(diào)用run方法
    thread.run();
    //當線程結(jié)束時,start方法不能調(diào)用,下面的方法將會拋出異常
    thread.start();
參考資料

文章有不當之處,歡迎指正,你也可以關(guān)注我的微信公眾號:好好學java,獲取優(yōu)質(zhì)學習資源。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • 進程和線程 進程 所有運行中的任務通常對應一個進程,當一個程序進入內(nèi)存運行時,即變成一個進程.進程是處于運行過程中...
    小徐andorid閱讀 2,989評論 3 53
  • 給大家分享我收藏的幾個不錯的 github 項目,內(nèi)容都還是不錯的,如果覺得有幫助,可以順便給個 star。計算機...
    程序員歐陽閱讀 2,049評論 3 81
  • Java多線程學習 [-] 一擴展javalangThread類 二實現(xiàn)javalangRunnable接口 三T...
    影馳閱讀 3,107評論 1 18
  • 本文主要講了java中多線程的使用方法、線程同步、線程數(shù)據(jù)傳遞、線程狀態(tài)及相應的一些線程函數(shù)用法、概述等。 首先講...
    李欣陽閱讀 2,597評論 1 15
  • https 問題的解決 這里時候后臺自己生成的免費證書 1.找后臺要一個生成的cer文件 2.直接拖進你的工程里...
    liulianjianshu閱讀 736評論 0 0

友情鏈接更多精彩內(nèi)容