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

一仰坦、初識(shí)

java的線程是通過java.lang.Thread類來實(shí)現(xiàn)的。VM啟動(dòng)時(shí)會(huì)有一個(gè)由主方法所定義的線程吊骤《懈冢可以通過創(chuàng)建Thread的實(shí)例來創(chuàng)建新的線程。每個(gè)線程都是通過某個(gè)特定Thread對(duì)象所對(duì)應(yīng)的方法run()來完成其操作的白粉,方法run()稱為線程體传泊。通過調(diào)用Thread類的start()方法來啟動(dòng)一個(gè)線程鼠渺。

在Java當(dāng)中,線程通常都有五種狀態(tài)眷细,創(chuàng)建拦盹、就緒、運(yùn)行溪椎、阻塞和死亡普舆。

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

第二是就緒狀態(tài)歉秫。當(dāng)調(diào)用了線程對(duì)象的start方法之后蛾洛,該線程就進(jìn)入了就緒狀態(tài),但是此時(shí)線程調(diào)度程序還沒有把該線程設(shè)置為當(dāng)前線程雁芙,此時(shí)處于就緒狀態(tài)轧膘。在線程運(yùn)行之后,從等待或者睡眠中回來之后兔甘,也會(huì)處于就緒狀態(tài)谎碍。

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

第四是阻塞狀態(tài)澡匪。線程正在運(yùn)行的時(shí)候扳碍,被暫停,通常是為了等待某個(gè)時(shí)間的發(fā)生(比如說某項(xiàng)資源就緒)之后再繼續(xù)運(yùn)行仙蛉。sleep,suspend,wait等方法都可以導(dǎo)致線程阻塞碱蒙。

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

二喷兼、start()方法

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

start()方法來啟動(dòng)線程季惯,真正實(shí)現(xiàn)了多線程運(yùn)行吠各。
start方法的作用就是將線程由NEW狀態(tài)臀突,變?yōu)镽UNABLE狀態(tài)。當(dāng)線程創(chuàng)建成功時(shí)贾漏,線程處于NEW(新建)狀態(tài)候学,如果你不調(diào)用start( )方法,那么線程永遠(yuǎn)處于NEW狀態(tài)纵散。調(diào)用start( )后梳码,才會(huì)變?yōu)镽UNABLE狀態(tài),線程才可以運(yùn)行伍掀。

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

線程不是馬上執(zhí)行的濒蒋;準(zhǔn)確來說,調(diào)用start( )方法后瘩例,線程的狀態(tài)是“READY(就緒)”狀態(tài)啊胶,而不是“RUNNING(運(yùn)行中)”狀態(tài)(關(guān)于線程的狀態(tài)詳細(xì)。線程要等待CPU調(diào)度垛贤,不同的JVM有不同的調(diào)度算法焰坪,線程何時(shí)被調(diào)度是未知的。因此聘惦,start()方法的被調(diào)用順序不能決定線程的執(zhí)行順序

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

三、run( )方法

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

run()方法當(dāng)作普通方法的方式調(diào)用
run( )其實(shí)是一個(gè)普通方法曹洽,只不過當(dāng)線程調(diào)用了start( )方法后鳍置,一旦線程被CPU調(diào)度,處于運(yùn)行狀態(tài)送淆,那么線程才會(huì)去調(diào)用這個(gè)run()方法税产;

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

上面說了,run()方法是一個(gè)普通的對(duì)象方法辟拷,因此撞羽,不需要線程調(diào)用start()后才可以調(diào)用的∥嗉妫可以線程對(duì)象可以隨時(shí)隨地調(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

再看另一個(gè)實(shí)例:

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

這個(gè)輸出結(jié)果不是固定的,因?yàn)榫€程的運(yùn)行沒法預(yù)測(cè)羽杰。運(yùn)行結(jié)果可能不一樣渡紫。

MyTask 類:

//實(shí)現(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方法啟動(dòng)線程

    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);  //模擬耗時(shí)任務(wù)  
                }  
            } 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);  //模擬耗時(shí)任務(wù)  
                }  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
        }  
    }  

結(jié)果:

這里寫圖片描述

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

2惕澎、先用run方法啟動(dòng)線程
將上面的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();  
        }  
      
    }  
這里寫圖片描述

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

總結(jié):

通過實(shí)例1和實(shí)例和我們可以知道start方法是用于啟動(dòng)線程的颜骤,可以實(shí)現(xiàn)并發(fā)唧喉,而run方法只是一個(gè)普通方法,是不能實(shí)現(xiàn)并發(fā)的忍抽,只是在并發(fā)執(zhí)行的時(shí)候會(huì)調(diào)用八孝。

說到這,不知道小伙伴們有沒有明白這兩個(gè)方法的區(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()啟動(dòng)線程,新線程會(huì)調(diào)用run()方法  
            start0();  
            // 設(shè)置started標(biāo)記=true  
            started = true;  
        } finally {  
            try {  
                if (!started) {  
                    group.threadStartFailed(this);  
                }  
            } catch (Throwable ignore) {  
            }  
        }  
    }  
public void run() {  
    if (target != null) {  
        target.run();  
    }  
} 

五牧抽、真正理解Thread類

Thread類的對(duì)象其實(shí)也是一個(gè)java對(duì)象嘉熊,只不過每一個(gè)Thread類的對(duì)象對(duì)應(yīng)著一個(gè)線程。Thread類的對(duì)象就是提供給用戶用于操作線程扬舒、獲取線程的信息阐肤。真正的底層線程用戶是看不到的了。
因此讲坎,當(dāng)一個(gè)線程結(jié)束了泽腮,死掉了,對(duì)應(yīng)的Thread的對(duì)象仍能調(diào)用衣赶,除了start( )方法外的所有方法(死亡的線程不能再次啟動(dòng)),如run( )厚满、getName( )府瞄、getPriority()等等

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

文章有不當(dāng)之處秆撮,歡迎指正,你也可以關(guān)注我的微信公眾號(hào):好好學(xué)java换况,獲取優(yōu)質(zhì)學(xué)習(xí)資源职辨。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市戈二,隨后出現(xiàn)的幾起案子舒裤,更是在濱河造成了極大的恐慌,老刑警劉巖觉吭,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件腾供,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡鲜滩,警方通過查閱死者的電腦和手機(jī)伴鳖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來徙硅,“玉大人榜聂,你說我怎么就攤上這事∶朴危” “怎么了峻汉?”我有些...
    開封第一講書人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長脐往。 經(jīng)常有香客問我休吠,道長,這世上最難降的妖魔是什么业簿? 我笑而不...
    開封第一講書人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任瘤礁,我火速辦了婚禮,結(jié)果婚禮上梅尤,老公的妹妹穿的比我還像新娘柜思。我一直安慰自己,他們只是感情好巷燥,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開白布赡盘。 她就那樣靜靜地躺著,像睡著了一般缰揪。 火紅的嫁衣襯著肌膚如雪陨享。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,541評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音抛姑,去河邊找鬼赞厕。 笑死,一個(gè)胖子當(dāng)著我的面吹牛定硝,可吹牛的內(nèi)容都是我干的皿桑。 我是一名探鬼主播,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蔬啡,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼诲侮!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起星爪,我...
    開封第一講書人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤浆西,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后顽腾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體近零,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年抄肖,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了久信。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡漓摩,死狀恐怖裙士,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情管毙,我是刑警寧澤腿椎,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布,位于F島的核電站夭咬,受9級(jí)特大地震影響啃炸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜卓舵,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一南用、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧掏湾,春花似錦裹虫、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至尊浪,卻和暖如春匣屡,著一層夾襖步出監(jiān)牢的瞬間涩拙,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來泰國打工耸采, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人工育。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓虾宇,卻偏偏與公主長得像,于是被迫代替她去往敵國和親如绸。 傳聞我的和親對(duì)象是個(gè)殘疾皇子嘱朽,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

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