Java線程的6種狀態(tài)詳解及創(chuàng)建線程的4種方式


某一天你在面試時(shí)遇到了線程的相關(guān)問(wèn)題。
面試官:“你知道有哪幾種創(chuàng)建線程的方式嗎桶唐?”
(此時(shí)你的心理活動(dòng):哈哈小意思這能難住我栅葡,忍住激動(dòng)假裝淡定道)
你:“嗯,可以通過(guò)實(shí)現(xiàn) Runnable 接口和繼承 Thread 類來(lái)創(chuàng)建線程尤泽⌒来兀”
面試官:“除了這兩種還有其他方式嗎?”
你:“emmm...還有嗎坯约?”
面試官:“知道通過(guò)實(shí)現(xiàn) Callable 接口與獲取 Future 對(duì)象來(lái)實(shí)現(xiàn)嗎熊咽?”
你:“emmm不知道...不過(guò)現(xiàn)在知道了嘻嘻”
面試官:“那創(chuàng)建線程池有哪些方式呢?”
你:“可以通過(guò) ThreadPoolExecutor 構(gòu)造函數(shù)或者 Executors 提供的工廠方法來(lái)創(chuàng)建”
面試官:“那通過(guò)不同的 Executors 工廠方法創(chuàng)建線程池之間有什么區(qū)別呢闹丐?”
你:“emmm...“
面試官:“那 ThreadPoolExecutor 構(gòu)造函數(shù)中的工作隊(duì)列和拒絕策略分別有哪些呢横殴?”
你:“emmm...“
(此時(shí)你的心理活動(dòng):QAQ...不面了,把勞資簡(jiǎn)歷還我卿拴!)

1衫仑、線程的定義

概念:線程是進(jìn)程中執(zhí)行運(yùn)算的最小單位,是進(jìn)程中的一個(gè)實(shí)體堕花,是被系統(tǒng)獨(dú)立調(diào)度和分派的基本單位文狱,線程自己不擁有系統(tǒng)資源,只擁有一點(diǎn)在運(yùn)行中必不可少的資源缘挽,但它可與同屬一個(gè)進(jìn)程的其它線程共享進(jìn)程所擁有的全部資源瞄崇。一個(gè)線程可以創(chuàng)建和撤消另一個(gè)線程,同一進(jìn)程中的多個(gè)線程之間可以并發(fā)執(zhí)行壕曼。

2杠袱、線程6種狀態(tài)及切換

Java中線程的狀態(tài)分為6種,定義在Thread類的State枚舉中窝稿。

public class Thread implements Runnable {
    ...
    public enum State {
        NEW,
        RUNNABLE,
        BLOCKED,
        WAITING,
        TIMED_WAITING,
        TERMINATED;
    }
    ...
}

NEW:初始狀態(tài)楣富,創(chuàng)建一個(gè)線程對(duì)象時(shí)就是該狀態(tài)。
RUNNABLE:運(yùn)行狀態(tài)伴榔,它包含了就緒(READY)和運(yùn)行中(RUNNING)兩種狀態(tài)纹蝴。當(dāng)線程對(duì)象創(chuàng)建后,調(diào)用該對(duì)象的 start() 方法就會(huì)進(jìn)入就緒狀態(tài)(READY)踪少。該狀態(tài)的線程位于可運(yùn)行線程池中塘安,等待被線程調(diào)度選中,獲取 CPU 的使用權(quán)援奢,在獲得 CPU 時(shí)間片后會(huì)變?yōu)檫\(yùn)行中狀態(tài)(RUNNING)兼犯。
BLOCKED:阻塞狀態(tài),表示線程此時(shí)阻塞于鎖。
WAITING:等待狀態(tài)切黔,進(jìn)入該狀態(tài)的線程需要等待其他線程做出一些特定動(dòng)作(通知或中斷)砸脊。
TIMED_WAITING:超時(shí)等待狀態(tài),該狀態(tài)與 WAITING 的不同點(diǎn)在于它可以在指定的時(shí)間后自行返回纬霞。
TERMINATED:終止?fàn)顟B(tài)凌埂,表示該線程已經(jīng)執(zhí)行完。

注意下圖狀態(tài)之間的切換诗芜。


線程六種狀態(tài)切換

</br>

3瞳抓、線程的四種創(chuàng)建方式

3.1、實(shí)現(xiàn) Runnable 接口

Runnable接口源碼如下伏恐,它只有一個(gè)run()方法孩哑。

public interface Runnable {
    public abstract void run();
}

示例:

public class ThreadDemo implements Runnable {
 
    @Override
    public void run() {
        System.out.println("通過(guò)實(shí)現(xiàn) Runnable 接口創(chuàng)建線程");
    }
 
    public static void main(String[] args) {
        ThreadDemo threadDemo = new ThreadDemo();
        Thread thread = new Thread(threadDemo);
        thread.start();
    }
    
}

3.2、繼承 Thread 類

示例:

public class ThreadDemo extends Thread {
 
    @Override
    public void run() {
        System.out.println("通過(guò)繼承 Thread 類創(chuàng)建線程");
    }
 
    public static void main(String[] args) {
        ThreadDemo threadDemo = new ThreadDemo();
        Thread thread = new Thread(threadDemo);
        thread.start();
    }
    
}

3.3翠桦、通過(guò) Callable臭笆、Future

通過(guò)實(shí)現(xiàn) Runnable 接口與繼承 Thread 類的方式創(chuàng)建的線程是沒(méi)有返回值的,然而在有些情況下秤掌,往往需要通過(guò)某個(gè)線程計(jì)算得到的結(jié)果供給另一個(gè)線程使用愁铺,這個(gè)時(shí)候采用Runnable 與 Thread 創(chuàng)建線程并通過(guò)自行編寫(xiě)代碼實(shí)現(xiàn)結(jié)果返回的方式會(huì)不可避免的出現(xiàn)許多錯(cuò)誤或性能上的問(wèn)題∥偶基于此問(wèn)題茵乱,JUC并發(fā)包(java.util.concurrent)提供了解決方案,實(shí)現(xiàn) Callable 的 call() 方法(這個(gè)類似Runnable 接口)孟岛,使用 Future 的 get() 方法進(jìn)行獲取瓶竭。
先來(lái)看一下Callable接口:

public interface Callable<V> {
    V call() throws Exception;
}

創(chuàng)建過(guò)程為:
1、自定義一個(gè)類實(shí)現(xiàn)Callable接口渠羞,重寫(xiě)call()方法斤贰;
2、使用JUC包下的 ExecutorService 生成一個(gè)對(duì)象次询,使用 submit() 方法得到 Future 對(duì)象荧恍;
3、采用 Future 的 get() 方法獲取返回值屯吊。
示例:

import java.util.concurrent.*;
 
/**
 * 計(jì)算1+2+...+20的結(jié)果送巡,開(kāi)啟三個(gè)線程,主線程獲取兩個(gè)子線程計(jì)算的結(jié)果盒卸,一個(gè)子線程計(jì)算1+...+10骗爆,一個(gè)子線程計(jì)算11+...+20。
 */
public class ThreadDemo implements Callable {

    //子線程1蔽介,用來(lái)計(jì)算1+...+10
    @Override
    public Object call() throws Exception {
        int count = 0;
        for (int i = 1; i <= 10; i++)
            count = count + i;
        return count;
    }
 
    public static void main(String[] args) throws Exception {
        //生成具有兩個(gè)線程的線程池
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        //調(diào)用 executorService.submit() 方法獲取 Future 對(duì)象
        Future<Integer> result1 = executorService.submit(new ThreadDemo());
        Future<Integer> result2 = executorService.submit(new SubThread());
        //使用 Future的get() 方法等待子線程計(jì)算完成返回的結(jié)果
        int result = result1.get() + result2.get();
        //關(guān)閉線程池
        executorService.shutdown();
        System.out.println(result);
    }
    
}
 
class SubThread implements Callable {

    //子線程2摘投,用來(lái)計(jì)算11+...+20
    @Override
    public Object call() throws Exception {
        int count = 0;
        for (int i = 11; i <= 20; i++)
            count = count + i;
        return count;
    }
    
}

3.4煮寡、通過(guò) JUC 里面的線程池

Executors 的工廠方法提供了 5 種不同的線程池,具體可以看JDK API犀呼,如下圖幸撕。



其實(shí)在3.3、通過(guò) Callable圆凰、Future 方式創(chuàng)建線程的示例就能看到通過(guò)Executors.newFixedThreadPool(2) 工廠方法構(gòu)建線程池杈帐。(Executors 的五種工廠方法的區(qū)別及優(yōu)缺點(diǎn)這里就不說(shuō)了体箕,下章再細(xì)說(shuō))

4专钉、幾個(gè)常見(jiàn)的線程面試題

4.1、線程與進(jìn)程的區(qū)別

???????進(jìn)程是操作系統(tǒng)進(jìn)行資源分配的單元累铅,線程是CPU調(diào)度運(yùn)行的單位跃须;一個(gè)進(jìn)程中可以包含很多線程,線程共享進(jìn)程的內(nèi)存等資源娃兽;每個(gè)進(jìn)程擁有各自獨(dú)立的一套變量菇民,相互不影響,而線程則共享數(shù)據(jù)投储,會(huì)存在線程安全問(wèn)題第练。

4.2、Thread 的 sleep() 方法和 wait() 方法有什么區(qū)別和共同點(diǎn)?

相同點(diǎn):

  • 兩者都可以暫停線程的執(zhí)行玛荞,都會(huì)讓線程進(jìn)入等待狀態(tài)娇掏。

不同點(diǎn):

  • sleep() 方法沒(méi)有釋放鎖,而 wait() 方法釋放了鎖勋眯。
  • sleep() 方法屬于 Thread 類的靜態(tài)方法婴梧,作用于當(dāng)前線程;而 wait() 方法是 Object 類的實(shí)例方法客蹋,作用于對(duì)象本身塞蹭。
  • 執(zhí)行 sleep() 方法后,可以通過(guò)超時(shí)或者調(diào)用 interrupt() 方法喚醒休眠中的線程讶坯;執(zhí)行 wait() 方法后番电,通過(guò)調(diào)用 notify() 或 notifyAll() 方法喚醒等待線程。

4.3辆琅、為什么啟動(dòng)線程時(shí)是調(diào)用 start() 方法而不是直接調(diào)用 run() 方法钧舌?

???????new 一個(gè) Thread 時(shí),線程會(huì)進(jìn)入初始狀態(tài)涎跨;調(diào)用 start() 方法時(shí)洼冻,會(huì)啟動(dòng)一個(gè)線程并使線程進(jìn)入就緒狀態(tài),當(dāng)分配到時(shí)間片后就可以開(kāi)始運(yùn)行了隅很。 start() 會(huì)執(zhí)行線程的相應(yīng)準(zhǔn)備工作撞牢,然后自動(dòng)執(zhí)行 run() 方法的內(nèi)容率碾,這是真正的多線程工作。 而直接執(zhí)行 run() 方法屋彪,會(huì)把 run() 方法當(dāng)成一個(gè) main 線程下的普通方法去執(zhí)行所宰,并不會(huì)在某個(gè)線程中執(zhí)行它,所以這并不是多線程工作畜挥。
  一句話總結(jié)就是調(diào)用 start() 方法可啟動(dòng)線程并使線程進(jìn)入就緒狀態(tài)仔粥,而 run() 方法只是 Thread 的一個(gè)普通方法調(diào)用,還是在主線程里執(zhí)行蟹但。

5躯泰、總結(jié)

通過(guò)本文希望能對(duì)你 Java 線程相關(guān)的知識(shí)掌握和面試能有所幫助,下章繼續(xù)介紹線程池的相關(guān)知識(shí)华糖。文中有錯(cuò)誤的地方麦向,還請(qǐng)留言給予指正,謝謝客叉。喜歡文章的小伙伴們可以關(guān)注點(diǎn)贊收藏哦~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末诵竭,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子兼搏,更是在濱河造成了極大的恐慌卵慰,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,907評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件佛呻,死亡現(xiàn)場(chǎng)離奇詭異裳朋,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)件相,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門再扭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人夜矗,你說(shuō)我怎么就攤上這事泛范。” “怎么了紊撕?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,298評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵罢荡,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我对扶,道長(zhǎng)区赵,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,586評(píng)論 1 293
  • 正文 為了忘掉前任浪南,我火速辦了婚禮笼才,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘络凿。我一直安慰自己骡送,他們只是感情好昂羡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著摔踱,像睡著了一般虐先。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上派敷,一...
    開(kāi)封第一講書(shū)人閱讀 51,488評(píng)論 1 302
  • 那天蛹批,我揣著相機(jī)與錄音,去河邊找鬼篮愉。 笑死腐芍,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的潜支。 我是一名探鬼主播甸赃,決...
    沈念sama閱讀 40,275評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼柿汛,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼冗酿!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起络断,我...
    開(kāi)封第一講書(shū)人閱讀 39,176評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤裁替,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后貌笨,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體弱判,經(jīng)...
    沈念sama閱讀 45,619評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評(píng)論 3 336
  • 正文 我和宋清朗相戀三年锥惋,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了昌腰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,932評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡膀跌,死狀恐怖遭商,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情捅伤,我是刑警寧澤劫流,帶...
    沈念sama閱讀 35,655評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站丛忆,受9級(jí)特大地震影響祠汇,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜熄诡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評(píng)論 3 329
  • 文/蒙蒙 一可很、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧凰浮,春花似錦我抠、人聲如沸姜骡。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,871評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)圈澈。三九已至,卻和暖如春尘惧,著一層夾襖步出監(jiān)牢的瞬間康栈,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,994評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工喷橙, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留啥么,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,095評(píng)論 3 370
  • 正文 我出身青樓贰逾,卻偏偏與公主長(zhǎng)得像悬荣,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子疙剑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評(píng)論 2 354