Java中線程的狀態(tài)

線程在一定條件下凑队,狀態(tài)會發(fā)生變化缀台。線程一共有以下幾種狀態(tài):
1、新建狀態(tài)(New):新創(chuàng)建了一個線程對象凭疮。
2饭耳、就緒狀態(tài)(Runnable):線程對象創(chuàng)建后,其他線程調用了該對象的start()方法执解。該狀態(tài)的線程位于“可運行線程池”中寞肖,變得可運行,只等待獲取CPU的使用權衰腌。即在就緒狀態(tài)的進程除CPU之外新蟆,其它的運行所需資源都已全部獲得。
3右蕊、運行狀態(tài)(Running):就緒狀態(tài)的線程獲取了CPU琼稻,執(zhí)行程序代碼。
4饶囚、阻塞狀態(tài)(Blocked):阻塞狀態(tài)是線程因為某種原因放棄CPU使用權帕翻,暫時停止運行。直到線程進入就緒狀態(tài)萝风,才有機會轉到運行狀態(tài)嘀掸。
阻塞的情況分三種:

  • (1)、等待阻塞:運行的線程執(zhí)行wait()方法规惰,該線程會釋放占用的所有資源睬塌,JVM會把該線程放入“等待池”中。進入這個狀態(tài)后卿拴,是不能自動喚醒的衫仑,必須依靠其他線程調用notify()或notifyAll()方法才能被喚醒,
  • (2)堕花、同步阻塞:運行的線程在獲取對象的同步鎖時文狱,若該同步鎖被別的線程占用,則JVM會把該線程放入“鎖池”中缘挽。
  • (3)瞄崇、其他阻塞:運行的線程執(zhí)行sleep()或join()方法呻粹,或者發(fā)出了I/O請求時,JVM會把該線程置為阻塞狀態(tài)苏研。當sleep()狀態(tài)超時等浊、join()等待線程終止或者超時、或者I/O處理完畢時摹蘑,線程重新轉入就緒狀態(tài)筹燕。

5、死亡狀態(tài)(Dead):線程執(zhí)行完了或者因異常退出了run()方法衅鹿,該線程結束生命周期撒踪。
線程變化的狀態(tài)轉換圖如下:


注:拿到對象的鎖標記,即為獲得了對該對象(臨界區(qū))的使用權限大渤。即該線程獲得了運行所需的資源制妄,進入“就緒狀態(tài)”,只需獲得CPU泵三,就可以運行耕捞。因為當調用wait()后,線程會釋放掉它所占有的“鎖標志”烫幕,所以線程只有在此獲取資源才能進入就緒狀態(tài)俺抽。
下面小小的作下解釋:

  • 1、線程的實現(xiàn)有兩種方式纬霞,一是繼承Thread類凌埂,二是實現(xiàn)Runnable接口,但不管怎樣诗芜, 當我們new了這個對象后瞳抓,線程就進入了初始狀態(tài);
  • 2伏恐、當該對象調用了start()方法孩哑,就進入就緒狀態(tài);
  • 3翠桦、進入就緒后横蜒,當該對象被操作系統(tǒng)選中,獲得CPU時間片就會進入運行狀態(tài)销凑;
  • 4丛晌、進入運行狀態(tài)后情況就比較復雜了
    • 4.1、run()方法或main()方法結束后斗幼,線程就進入終止狀態(tài)澎蛛;
    • 4.2、當線程調用了自身的sleep()方法或其他線程的join()方法蜕窿,進程讓出CPU谋逻,然后就會進入阻塞狀態(tài)(該狀態(tài)既停止當前線程呆馁,但并不釋放所占有的資源****即調用sleep ()函數(shù)后,線程不會釋放它的“鎖標志”毁兆。)浙滤。當sleep()結束或join()結束后,該線程進入可運行狀態(tài)气堕,繼續(xù)等待OS分配CPU時間片纺腊。典型地,****sleep()被用在等待某個資源就緒的情形:測試發(fā)現(xiàn)條件不滿足后送巡,讓線程阻塞一段時間后重新測試摹菠,直到條件滿足為止盒卸。
    • 4.3骗爆、線程調用了yield()方法,意思是放棄當前獲得的CPU時間片蔽介,回到就緒狀態(tài)摘投,這時與其他進程處于同等競爭狀態(tài),OS有可能會接著又讓這個進程進入運行狀態(tài)虹蓄; 調用 yield() 的效果等價于調度程序認為該線程已執(zhí)行了足夠的時間片從而需要轉到另一個線程犀呼。yield()只是使當前線程重新回到可執(zhí)行狀態(tài),所以執(zhí)行yield()的線程有可能在進入到可執(zhí)行狀態(tài)后馬上又被執(zhí)行薇组。
    • 4.4外臂、當線程剛進入可運行狀態(tài)(注意,還沒運行)律胀,發(fā)現(xiàn)將要調用的資源被synchroniza(同步)宋光,獲取不到鎖標記,將會立即進入鎖池狀態(tài)炭菌,等待獲取鎖標記(這時的鎖池里也許已經有了其他線程在等待獲取鎖標記罪佳,這時它們處于隊列狀態(tài),既先到先得)黑低,一旦線程獲得鎖標記后赘艳,就轉入就緒狀態(tài),等待OS分配CPU時間片克握;
    • 4.5蕾管、suspend() 和 resume()方法:兩個方法配套使用,suspend()使得線程進入阻塞狀態(tài)菩暗,并且不會自動恢復掰曾,必須其對應的resume()被調用,才能使得線程重新進入可執(zhí)行狀態(tài)勋眯。典型地婴梧,****suspend()和 resume() 被用在等待另一個線程產生的結果的情形:**測試發(fā)現(xiàn)結果還沒有產生后下梢,讓線程阻塞,另一個線程產生了結果后塞蹭,調用 resume()使其恢復孽江。
    • ** 4.6****、wait()和 notify() 方法:當線程調用wait()方法后會進入等待隊列(進入這個狀態(tài)會釋放所占有的所有資源番电,與阻塞狀態(tài)不同**)岗屏,進入這個狀態(tài)后,是不能自動喚醒的漱办,必須依靠其他線程調用notify()或notifyAll()方法才能被喚醒(由于notify()只是喚醒一個線程这刷,但我們由不能確定具體喚醒的是哪一個線程,也許我們需要喚醒的線程不能夠被喚醒娩井,因此在實際使用時暇屋,一般都用notifyAll()方法,喚醒有所線程)洞辣,線程被喚醒后會進入鎖池咐刨,等待獲取鎖標記。

wait() 使得線程進入阻塞狀態(tài)扬霜,它有兩種形式:

  • 一種允許指定以毫秒為單位的一段時間作為參數(shù)定鸟;
  • 另一種沒有參數(shù)。

前者當對應的 notify()被調用或者超出指定時間時線程重新進入可執(zhí)行狀態(tài)即就緒狀態(tài)著瓶,后者則必須對應的 notify()被調用联予。當調用wait()后,線程會釋放掉它所占有的“鎖標志”材原,從而使線程所在對象中的其它synchronized數(shù)據(jù)可被別的線程使用沸久。waite()和notify()因為會對對象的“鎖標志”進行操作,所以它們必須在synchronized函數(shù)或synchronizedblock中進行調用华糖。如果在non-synchronized函數(shù)或non-synchronizedblock中進行調用麦向,雖然能編譯通過,但在運行時會發(fā)生IllegalMonitorStateException的異常客叉。

注意區(qū)別:初看起來wait() 和 notify() 方法與suspend()和 resume() 方法對沒有什么分別诵竭,但是事實上它們是截然不同的。區(qū)別的核心在于兼搏,前面敘述的suspend()及其它所有方法在線程阻塞時都不會釋放占用的鎖(如果占用了的話)卵慰,而wait() 和 notify() 這一對方法則相反。

上述的核心區(qū)別導致了一系列的細節(jié)上的區(qū)別

  • 首先佛呻,前面敘述的所有方法都隸屬于 Thread類裳朋,但是wait() 和 notify() 方法這一對卻直接隸屬于 Object 類也就是說吓著,所有對象都擁有這一對方法鲤嫡。初看起來這十分不可思議送挑,但是實際上卻是很自然的,因為這一對方法阻塞時要釋放占用的鎖暖眼,而鎖是任何對象都具有的惕耕,調用任意對象的 wait() 方法導致線程阻塞,并且該對象上的鎖被釋放诫肠。而調用任意對象的notify()方法則導致因調用該對象的 wait()方法而阻塞的線程中隨機選擇的一個解除阻塞(但要等到獲得鎖后才真正可執(zhí)行)司澎。
  • 其次,前面敘述的所有方法都可在任何位置調用栋豫,但是wait() 和 notify() 方法這一對方法卻必須在 synchronized 方法或塊中調用挤安,理由也很簡單,只有在synchronized方法或塊中當前線程才占有鎖丧鸯,才有鎖可以釋放蛤铜。同樣的道理,調用這一對方法的對象上的鎖必須為當前線程所擁有骡送,這樣才有鎖可以釋放昂羡。因此,這一對方法調用必須放置在這樣的 synchronized方法或塊中摔踱,該方法或塊的上鎖對象就是調用這一對方法的對象。若不滿足這一條件怨愤,則程序雖然仍能編譯派敷,但在運行時會出現(xiàn)IllegalMonitorStateException異常。
  • wait() 和 notify()方法的上述特性決定了它們經常和synchronized方法或塊一起使用撰洗,將它們和操作系統(tǒng)的進程間通信機制作一個比較就會發(fā)現(xiàn)它們的相似性:synchronized方法或塊提供了類似于操作系統(tǒng)原語的功能篮愉,它們的執(zhí)行不會受到多線程機制的干擾,而這一對方法則相當于 block和wake up 原語(這一對方法均聲明為 synchronized)差导。它們的結合使得我們可以實現(xiàn)操作系統(tǒng)上一系列精妙的進程間通信的算法(如信號量算法)试躏,并用于解決各種復雜的線程間通信問題。

關于 wait() 和 notify() 方法最后再說明兩點:

  • 第一:調用notify() 方法導致解除阻塞的線程是從因調用該對象的 wait()方法而阻塞的線程中隨機選取的设褐,我們無法預料哪一個線程將會被選擇颠蕴,所以編程時要特別小心,避免因這種不確定性而產生問題助析。
  • 第二:除了notify()犀被,還有一個方法 notifyAll()也可起到類似作用,唯一的區(qū)別在于外冀,調用 notifyAll()方法將把因調用該對象的 wait()方法而阻塞的所有線程一次性全部解除阻塞寡键。當然,只有獲得鎖的那一個線程才能進入可執(zhí)行狀態(tài)雪隧。

談到阻塞西轩,就不能不談一談死鎖员舵,略一分析就能發(fā)現(xiàn),suspend()方法和不指定超時期限的wait()方法的調用都可能產生死鎖藕畔。遺憾的是固灵,Java并不在語言級別上支持死鎖的避免,我們在編程中必須小心地避免死鎖

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末劫流,一起剝皮案震驚了整個濱河市巫玻,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌祠汇,老刑警劉巖仍秤,帶你破解...
    沈念sama閱讀 217,734評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異可很,居然都是意外死亡诗力,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評論 3 394
  • 文/潘曉璐 我一進店門我抠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來苇本,“玉大人,你說我怎么就攤上這事菜拓“暾” “怎么了?”我有些...
    開封第一講書人閱讀 164,133評論 0 354
  • 文/不壞的土叔 我叫張陵纳鼎,是天一觀的道長俺夕。 經常有香客問我,道長贱鄙,這世上最難降的妖魔是什么劝贸? 我笑而不...
    開封第一講書人閱讀 58,532評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮逗宁,結果婚禮上映九,老公的妹妹穿的比我還像新娘。我一直安慰自己瞎颗,他們只是感情好件甥,可當我...
    茶點故事閱讀 67,585評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著言缤,像睡著了一般嚼蚀。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上管挟,一...
    開封第一講書人閱讀 51,462評論 1 302
  • 那天轿曙,我揣著相機與錄音,去河邊找鬼。 笑死导帝,一個胖子當著我的面吹牛守谓,可吹牛的內容都是我干的。 我是一名探鬼主播您单,決...
    沈念sama閱讀 40,262評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼斋荞,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了虐秦?” 一聲冷哼從身側響起平酿,我...
    開封第一講書人閱讀 39,153評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎悦陋,沒想到半個月后蜈彼,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 45,587評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡俺驶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,792評論 3 336
  • 正文 我和宋清朗相戀三年幸逆,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片暮现。...
    茶點故事閱讀 39,919評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡还绘,死狀恐怖,靈堂內的尸體忽然破棺而出栖袋,到底是詐尸還是另有隱情拍顷,我是刑警寧澤,帶...
    沈念sama閱讀 35,635評論 5 345
  • 正文 年R本政府宣布栋荸,位于F島的核電站菇怀,受9級特大地震影響,放射性物質發(fā)生泄漏晌块。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,237評論 3 329
  • 文/蒙蒙 一帅霜、第九天 我趴在偏房一處隱蔽的房頂上張望匆背。 院中可真熱鬧,春花似錦身冀、人聲如沸钝尸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,855評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽珍促。三九已至,卻和暖如春剩愧,著一層夾襖步出監(jiān)牢的瞬間猪叙,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,983評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留穴翩,地道東北人犬第。 一個月前我還...
    沈念sama閱讀 48,048評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像芒帕,于是被迫代替她去往敵國和親歉嗓。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,864評論 2 354

推薦閱讀更多精彩內容

  • 本文主要講了java中多線程的使用方法背蟆、線程同步鉴分、線程數(shù)據(jù)傳遞、線程狀態(tài)及相應的一些線程函數(shù)用法带膀、概述等志珍。 首先講...
    李欣陽閱讀 2,454評論 1 15
  • Java多線程學習 [-] 一擴展javalangThread類 二實現(xiàn)javalangRunnable接口 三T...
    影馳閱讀 2,957評論 1 18
  • 該文章轉自:http://blog.csdn.net/evankaka/article/details/44153...
    加來依藍閱讀 7,353評論 3 87
  • 寫在前面的話: 這篇博客是我從這里“轉載”的,為什么轉載兩個字加“”呢本砰?因為這絕不是簡單的復制粘貼碴裙,我花了五六個小...
    SmartSean閱讀 4,730評論 12 45
  • 本文出自 Eddy Wiki ,轉載請注明出處:http://eddy.wiki/interview-java.h...
    eddy_wiki閱讀 2,120評論 0 14