Java Thread知識點總結(jié)

簡介

什么是線程

進程:一個進程包括由操作系統(tǒng)分配的內(nèi)存空間,包含一個或多個線程奈懒。一個進程一直運行遭商,直到所有的非守護線程都結(jié)束運行后才能結(jié)束。
線程:一個線程不能獨立的存在缅帘,它必須是進程的一部分轴术。

線程的生命周期
生命周期

實現(xiàn)方式

大家可能在面試過程中、文章中或者書上看到過“實現(xiàn)線程有幾種方式钦无?”這樣的問題逗栽,基本都是千篇一律的說兩種方式:1、繼承Thread重寫run方法失暂;2彼宠、實現(xiàn)Runnable接口鳄虱。其實這里是有問題的,總所周知在Java中使用Thread表示線程的兵志,所以實現(xiàn)Thread只有一種方式:那就是構(gòu)造Thread類醇蝴。而實現(xiàn)線程的執(zhí)行單元有兩種方式:1、繼承Thread重寫run方法想罕;2悠栓、實現(xiàn)Runnable接口的run方法,并將Runnable實例作為構(gòu)造Thread的參數(shù)按价。

API講解

構(gòu)造函數(shù)
    public Thread() {
        init(null, null, "Thread-" + nextThreadNum(), 0);
    }

    public Thread(Runnable target) {
        init(null, target, "Thread-" + nextThreadNum(), 0);
    }

    public Thread(ThreadGroup group, Runnable target) {
        init(group, target, "Thread-" + nextThreadNum(), 0);
    }

    public Thread(String name) {
        init(null, null, name, 0);
    }

    public Thread(ThreadGroup group, String name) {
        init(group, null, name, 0);
    }

    public Thread(Runnable target, String name) {
        init(null, target, name, 0);
    }

    public Thread(ThreadGroup group, Runnable target, String name) {
        init(group, target, name, 0);
    }

    public Thread(ThreadGroup group, Runnable target, String name,
                  long stackSize) {
        init(group, target, name, stackSize);
    }
    
    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize) {
        init(g, target, name, stackSize, null);
    }
    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc) {
    ...
    }

強烈建議:在構(gòu)造線程的時候為線程取一個有特殊意義的名字惭适,有助于問題的排查和線程的跟蹤(特別是在線程比較多的程序中)。

Thread.sleep和TimeUnit

sleep()方法導(dǎo)致程序暫停執(zhí)行指定的時間楼镐,讓出cpu給其他線程癞志,但是他的監(jiān)控狀態(tài)依然保持者,當(dāng)指定的時間到了又會自動恢復(fù)運行狀態(tài)框产。在調(diào)用sleep()方法的過程中凄杯,線程不會釋放對象鎖。

sleep是一個靜態(tài)方法秉宿,有兩個重載方法戒突,其中一個需要傳入毫秒數(shù),另一個既需要毫秒數(shù)也需要納秒數(shù)描睦。

public static void sleep(long millis)
public static void sleep(long millis, int nanos)

TimeUnit是JDK1.5以后引入的膊存,其對sleep有更好的封裝性,能更好地忱叭、更精準(zhǔn)地控制隔崎。

TimeUnit.HOURS.sleep(1);
TimeUnit.MUNUTES.sleep(1);
TimeUnit.SECONDS.sleep(1);

強烈建議:用TimeUnit代替Thread.sleep,因為sleep能做的事韵丑,TimeUnit都能做并且功能更強大爵卒。

Thread.yield

yield方法屬于一種啟發(fā)式的方法,其會提醒調(diào)度器我愿意放棄當(dāng)前CPU資源撵彻。如果CPU資源不緊張钓株,則會忽略這種提醒。如果生效千康,會使當(dāng)前線程從Running狀態(tài)切換到Runnable狀態(tài)享幽。

new Thread(() -> {
    Thread.yield();
    System.out.println("yield");
  }
).start()
yield和sleep區(qū)別
  • sleep會導(dǎo)致線程暫停指定時間铲掐,會使線程處于block狀態(tài)拾弃;yield如果CPU調(diào)度器沒有忽略,會導(dǎo)致線程處于Runnable狀態(tài)摆霉。
  • sleep幾乎百分之百地完成給定時間的休眠豪椿;yield并不能保證成功奔坟。
  • 一個線程sleep,另一個線程調(diào)用interrupt會捕獲到中斷信號搭盾;yield不會咳秉。
join

join()方法是Thread類中的一個方法,該方法的定義是等待該線程終止鸯隅。其實就是join()方法將掛起調(diào)用線程的執(zhí)行澜建,直到被調(diào)用的對象完成它的執(zhí)行。join與sleep一樣是一個可中斷的方法蝌以。

ThreadTest test  =new ThreadTest();
ThreadTest test2  =new ThreadTest();
test.setName("one");
test2.setName("two");
Thread t1 = new Thread(test);
Thread t2 = new Thread(test2);
t1.start();
/**
* 主線程向下轉(zhuǎn)時炕舵,碰到了t1.join(),t1要申請加入到運行中來,就是要CPU執(zhí)行權(quán)跟畅。
* 這時候CPU執(zhí)行權(quán)在主線程手里咽筋,主線程就把CPU執(zhí)行權(quán)給放開,陷入凍結(jié)狀態(tài)徊件。
* 活著的只有t1了奸攻,只有當(dāng)t1拿著執(zhí)行權(quán)把這些數(shù)據(jù)都打印完了,主線程才恢復(fù)到運行中來
*/
//join 方法 確保 t1執(zhí)行之后 執(zhí)行t2
t1.join();
t2.start();
join和CountDownLatch區(qū)別
  • 都適用“主程序中需要等待所有子線程完成后 再繼續(xù)任務(wù)”的場景
  • 調(diào)用join方法需要等待thread執(zhí)行完畢才能繼續(xù)向下執(zhí)行,而CountDownLatch只需要檢查計數(shù)器的值為零就可以繼續(xù)向下執(zhí)行虱痕,相比之下睹耐,CountDownLatch更加靈活一些,可以實現(xiàn)一些更加復(fù)雜的業(yè)務(wù)場景皆疹。
interrupt疏橄、interrupted、isInterrupted
interrupt

interrupt()方法: 作用是中斷線程略就。

  • 本線程中斷自身是被允許的捎迫,且"中斷標(biāo)記"設(shè)置為true
  • 其它線程調(diào)用本線程的interrupt()方法時,會通過checkAccess()檢查權(quán)限表牢。這有可能拋出SecurityException異常窄绒。
  • 若線程在阻塞狀態(tài)時,調(diào)用了它的interrupt()方法崔兴,那么它的“中斷狀態(tài)”會被清除并且會收到一個InterruptedException異常彰导。
    例如:線程通過wait()、sleep()敲茄、join()進入阻塞狀態(tài)位谋,此時通過interrupt()中斷該線程;調(diào)用interrupt()會立即將線程的中斷標(biāo)記設(shè)為“true”堰燎,但是由于線程處于阻塞狀態(tài)掏父,所以該“中斷標(biāo)記”會立即被清除為“false”,同時秆剪,會產(chǎn)生一個InterruptedException的異常赊淑。
    如果線程被阻塞在一個Selector選擇器中爵政,那么通過interrupt()中斷它時;線程的中斷標(biāo)記會被設(shè)置為true陶缺,并且它會立即從選擇操作中返回钾挟。
  • 如果不屬于前面所說的情況,那么通過interrupt()中斷線程時饱岸,它的中斷標(biāo)記會被設(shè)置為“true”掺出。
interrupted和isInterrupted
  • interrupted和isInterrupted都是判斷當(dāng)前線程是否被中斷
  • interrupted會清除掉線程的interrupt標(biāo)志;isInterrupted不會
        System.out.println("Main Thread is interrupted? " + Thread.interrupted());
        Thread.currentThread().interrupt();
        System.out.println("Main Thread is interrupted? " + Thread.currentThread().isInterrupted());
//        System.out.println("Main Thread is interrupted? " + Thread.interrupted());
        try {
            TimeUnit.MINUTES.sleep(1);
        } catch (InterruptedException e) {
            System.out.println("I will be interrupted still.");
        }

思考:打開注釋和關(guān)閉注釋的區(qū)別苫费?

如何關(guān)閉一個線程
  • 正常關(guān)閉
    1蛛砰、 線程正常結(jié)束,線程自動退出
    2黍衙、捕獲中斷信號
    3泥畅、適用volatile開關(guān)控制
  • 異常退出
    補充:Thread API中包含了一個stop()方法,可以突然終止線程琅翻。但它在JDK1.2后便被淘汰了位仁,因為它可能導(dǎo)致數(shù)據(jù)對象的崩潰。一個問題是方椎,當(dāng)線程終止時聂抢,很少有機會執(zhí)行清理工作;另一個問題是棠众,當(dāng)在某個線程上調(diào)用stop()方法時琳疏,線程釋放它當(dāng)前持有的所有鎖,持有這些鎖必定有某種合適的理由——也許是阻止其他線程訪問尚未處于一致性狀態(tài)的數(shù)據(jù)闸拿,突然釋放鎖可能使某些對象中的數(shù)據(jù)處于不一致狀態(tài)空盼,而且不會出現(xiàn)數(shù)據(jù)可能崩潰的任何警告。
守護線程

若JVM中沒有一個非守護線程時新荤,JVM的進行會退出揽趾。
守護線程具備自動結(jié)束生命周期的特性,經(jīng)常用于執(zhí)行一些后臺工作苛骨,因此有時它也被稱為后臺線程篱瞎。

//偽代碼如下
Thread thread = new Thread();
thread.setDaemon(true);
thread.start()
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市痒芝,隨后出現(xiàn)的幾起案子俐筋,更是在濱河造成了極大的恐慌,老刑警劉巖严衬,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件澄者,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機闷哆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來单起,“玉大人抱怔,你說我怎么就攤上這事∴值梗” “怎么了屈留?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長测蘑。 經(jīng)常有香客問我灌危,道長,這世上最難降的妖魔是什么碳胳? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任勇蝙,我火速辦了婚禮,結(jié)果婚禮上挨约,老公的妹妹穿的比我還像新娘味混。我一直安慰自己,他們只是感情好诫惭,可當(dāng)我...
    茶點故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布翁锡。 她就那樣靜靜地躺著,像睡著了一般夕土。 火紅的嫁衣襯著肌膚如雪馆衔。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天怨绣,我揣著相機與錄音角溃,去河邊找鬼。 笑死篮撑,一個胖子當(dāng)著我的面吹牛开镣,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播咽扇,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼邪财,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了质欲?” 一聲冷哼從身側(cè)響起树埠,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎嘶伟,沒想到半個月后怎憋,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年绊袋,在試婚紗的時候發(fā)現(xiàn)自己被綠了毕匀。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,617評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡癌别,死狀恐怖皂岔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情展姐,我是刑警寧澤躁垛,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布,位于F島的核電站圾笨,受9級特大地震影響教馆,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜擂达,卻給世界環(huán)境...
    茶點故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一土铺、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧板鬓,春花似錦舒憾、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至唤蔗,卻和暖如春探遵,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背妓柜。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工箱季, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人棍掐。 一個月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓藏雏,卻偏偏與公主長得像,于是被迫代替她去往敵國和親作煌。 傳聞我的和親對象是個殘疾皇子掘殴,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,486評論 2 348

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