Java線程筆記

前言

在運行一個Java線程之前需要構(gòu)造一個線程對象,在構(gòu)造線程對象的時候需要提供線程需要的屬性庄吼,比如線程組缎除、優(yōu)先級、是否是Daemon線程等信息总寻。調(diào)用start()去啟動線程器罐,是當前線程(parent線程)告知Java虛擬機,只要線程規(guī)劃器空閑渐行,就啟動調(diào)用了start()方法的線程轰坊。
接下來對以下7點做個概括:

  • 線程狀態(tài)
  • Daemon線程
  • 線程中斷
  • 過期的suspend()铸董、resume()、stop()
  • 安全地終止線程
  • 線程間通信(volatile肴沫、synchronized粟害、等待/通知、管道颤芬、join())
  • ThreadLocal

線程狀態(tài)

Java線程有6種不同的狀態(tài):

狀態(tài)名稱 說明
NEW 初始狀態(tài)悲幅,線程被創(chuàng)建,但是還沒有調(diào)用start()方法
RUNNABLE 運行狀態(tài)站蝠,Java線程將操作系統(tǒng)中的就緒和運行統(tǒng)稱為“運行中”
BLOCKED 阻塞狀態(tài)汰具,表示線程阻塞于鎖
WAITING 等待狀態(tài),表示線程進入等待狀態(tài)菱魔,需要其他線程進行一些特定操作(通知或中斷)才能返回
TIME_WAITING 超時等待狀態(tài)留荔,與WAITING不同,超時后會自動返回
TERMINATED 終止狀態(tài)澜倦,表示當前線程已經(jīng)執(zhí)行完畢

狀態(tài)之間的變遷如下:


Java線程的狀態(tài)變遷.png
  • 線程調(diào)用start()方法之后開始運行聚蝶;
  • 當調(diào)用線程的wait()方法之后進入等待狀態(tài),等待狀態(tài)下的線程需要其他線程調(diào)用notify()/notifyAll()方法之后才能返回運行狀態(tài)肥隆。而超時等待狀態(tài)加了超時限制既荚,達到超時時間之后會返回運行狀態(tài)稚失;
  • 當線程調(diào)用同步方法時栋艳,沒有獲得鎖的情況下,會進入阻塞狀態(tài)句各,獲取到鎖之后返回運行狀態(tài)吸占;
  • 線程執(zhí)行完Runable的run()方法之后進入終止狀態(tài);
  • 阻塞狀態(tài)是線程進入synchronized關(guān)鍵字修飾的方法或者代碼塊時的狀態(tài)凿宾;阻塞在java.concurrent包下的Lock接口則是等待狀態(tài)矾屯。

Daemon線程

Daemon線程是支持性線程,在程序后臺進行調(diào)度以及支持性工作初厚。這意味著件蚕,當虛擬機不存在非Daemon線程,那么Java虛擬機將會退出产禾。Daemon線程中finally塊的內(nèi)容將不會執(zhí)行排作,因此不能在Daemon線程的finally塊中做資源釋放工作。
通過Thread.setDaemon(true)來設(shè)置Daemon線程亚情,需要在start()方法調(diào)用之前設(shè)置妄痪。

線程中斷

中斷其實是線程中的一個標志位,其他線程通過調(diào)用該線程對象的interrupt()方法對其進行中斷操作楞件。線程對象通過檢查自身是否被中斷來進行響應(yīng)衫生,線程對象通過方法isInterrupted()來判斷是否被中斷裳瘪,也可以通過Thread.interrupted()來復位中斷標記位。如果線程處于終結(jié)狀態(tài)罪针,即使被調(diào)用了interrupt()方法彭羹,該線程對象的isInterrupted()返回的依然是false。還有許多聲明拋出InterruptedException的方法(例如sleep(long millis)方法)在拋出異常之前會清空中斷標識位(設(shè)置為false)站故。

過期的suspend()皆怕、resume()、stop()

調(diào)用suspend()之后西篓,線程不會釋放已經(jīng)占有的資源(比如鎖)愈腾,而是占有著資源進入睡眠狀態(tài),這樣容易引發(fā)死鎖問題岂津。調(diào)用stop()方法在終結(jié)一個線程時不會保證線程的資源正常釋放虱黄,通常是沒有給予線程完成資源釋放工作的機會,因此會導致程序可能工作在不確定狀態(tài)下吮成。

安全地終止線程

線程的掛起suspend()方法以及停止stop()方法都不能安全地終止線程橱乱,那么只通過中斷interrupt()方法來實現(xiàn)安全終止。

 class SaveShutdownRunnable implements Runnable {

        private volatile boolean mShutDown;
        private long i;

        @Override
        public void run() {

            while (!mShutDown && !Thread.currentThread().isInterrupted()) {
                i++;
            }
        }

        public void cancel(){
            mShutDown = true;
        }

    }

線程間通信(volatile粱甫、synchronized泳叠、等待/通知、管道茶宵、join())

任意一個對象都擁有自己的監(jiān)視器危纫,當這個對象由同步塊或者這個對象的同步方法調(diào)用時,執(zhí)行方法的線程必須先獲取該對象的監(jiān)視器才能進入同步塊或者同步方法乌庶,而沒有獲取到監(jiān)視器(執(zhí)行該方法)的線程將會被阻塞在同步塊和同步方法的入口處种蝶,進入BLOCKED狀態(tài)瞒大。
等待/通知機制,是指一個線程A調(diào)用了對象O的wait()方法進入等待狀態(tài)透敌,而另一個線程B調(diào)用了對象O的notify()或者notifyAll()方法酗电,線程A接收到通知之后從對象O的wait()方法返回,繼續(xù)執(zhí)行后續(xù)的操作泼疑。
等待/通知機制依托于同步機制,其目的就是確保等待線程從wait()方法返回時能夠感知到通知線程對變量做出的修改移稳』嵊停可以得出如下細節(jié):

  • 使用wait()notify()notifyAll()時需要先對調(diào)用對象加鎖都许;
  • 調(diào)用wait()方法后嫂冻,線程狀態(tài)由RUNNING變成WAITING,并將當期線程放置到對象的等待隊列;
  • notify()notifyAll()方法調(diào)用后睛低,等待線程依舊不會從wait()返回服傍,需要調(diào)用notify()notifyAll()的線程釋放鎖之后,等待線程才有機會從wait()返回吹零;
  • notify()方法將等待隊列中的一個等待線程從等待隊列中移到同步隊列中灿椅,而notifyAll()方法是將等待隊列中所有的線程全部移到同步隊列,被移動的線程狀態(tài)由WAITING變?yōu)锽LOCKED泣懊;
  • wait()方法返回的前提是獲得調(diào)用對象的鎖麻惶。
    等待/通知機制.png

    等待/通知的經(jīng)典范式
  • 等待方偽代碼:
// 獲得對象的鎖
synchronized(對象){
    // 條件不滿足則調(diào)用對象的wait()方法
    while(條件不滿足){
          對象.wait();
    }
    對應(yīng)的處理邏輯
}
  • 通知方偽代碼
// 獲得對象的鎖
synchronized(對象){
    改變條件
    對象.notifyAll();
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市静稻,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌杀迹,老刑警劉巖押搪,帶你破解...
    沈念sama閱讀 221,695評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異垂谢,居然都是意外死亡疮茄,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,569評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來畸裳,“玉大人躯畴,你說我怎么就攤上這事》峒危” “怎么了嚷缭?”我有些...
    開封第一講書人閱讀 168,130評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長路幸。 經(jīng)常有香客問我付翁,道長,這世上最難降的妖魔是什么砰识? 我笑而不...
    開封第一講書人閱讀 59,648評論 1 297
  • 正文 為了忘掉前任佣渴,我火速辦了婚禮辛润,結(jié)果婚禮上膨处,老公的妹妹穿的比我還像新娘。我一直安慰自己秦叛,他們只是感情好瀑粥,可當我...
    茶點故事閱讀 68,655評論 6 397
  • 文/花漫 我一把揭開白布狞换。 她就那樣靜靜地躺著,像睡著了一般查库。 火紅的嫁衣襯著肌膚如雪黄琼。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,268評論 1 309
  • 那天围苫,我揣著相機與錄音剂府,去河邊找鬼剃盾。 笑死,一個胖子當著我的面吹牛衰伯,可吹牛的內(nèi)容都是我干的积蔚。 我是一名探鬼主播,決...
    沈念sama閱讀 40,835評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼临扮,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了贪壳?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,740評論 0 276
  • 序言:老撾萬榮一對情侶失蹤钻注,失蹤者是張志新(化名)和其女友劉穎配猫,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體捆交,經(jīng)...
    沈念sama閱讀 46,286評論 1 318
  • 正文 獨居荒郊野嶺守林人離奇死亡品追,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,375評論 3 340
  • 正文 我和宋清朗相戀三年冯丙,在試婚紗的時候發(fā)現(xiàn)自己被綠了胃惜。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,505評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖捺弦,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情幽崩,我是刑警寧澤慌申,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布蹄溉,位于F島的核電站您炉,受9級特大地震影響赚爵,放射性物質(zhì)發(fā)生泄漏法瑟。R本人自食惡果不足惜唁奢,卻給世界環(huán)境...
    茶點故事閱讀 41,873評論 3 333
  • 文/蒙蒙 一麻掸、第九天 我趴在偏房一處隱蔽的房頂上張望脊奋。 院中可真熱鬧,春花似錦蒜埋、人聲如沸最楷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,357評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽适瓦。三九已至,卻和暖如春否彩,著一層夾襖步出監(jiān)牢的瞬間列荔,已是汗流浹背枚尼。 一陣腳步聲響...
    開封第一講書人閱讀 33,466評論 1 272
  • 我被黑心中介騙來泰國打工署恍, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留锭汛,地道東北人袭蝗。 一個月前我還...
    沈念sama閱讀 48,921評論 3 376
  • 正文 我出身青樓朵逝,卻偏偏與公主長得像啤咽,于是被迫代替她去往敵國和親宇整。 傳聞我的和親對象是個殘疾皇子芋膘,可洞房花燭夜當晚...
    茶點故事閱讀 45,515評論 2 359

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

  • 進程和線程 進程 所有運行中的任務(wù)通常對應(yīng)一個進程,當一個程序進入內(nèi)存運行時,即變成一個進程.進程是處于運行過程中...
    勝浩_ae28閱讀 5,117評論 0 23
  • 進程和線程 進程 所有運行中的任務(wù)通常對應(yīng)一個進程,當一個程序進入內(nèi)存運行時,即變成一個進程.進程是處于運行過程中...
    小徐andorid閱讀 2,814評論 3 53
  • 本文出自 Eddy Wiki 鳞青,轉(zhuǎn)載請注明出處:http://eddy.wiki/interview-java.h...
    eddy_wiki閱讀 2,146評論 0 14
  • 文章來源:http://www.54tianzhisheng.cn/2017/06/04/Java-Thread/...
    beneke閱讀 1,489評論 0 1
  • 1、概述 Java 給多線程編程提供了內(nèi)置的支持为朋。 一條線程指的是進程中一個單一順序的控制流臂拓,一個進程中可以并發(fā)多...
    高丕基閱讀 481評論 0 8