Java
淘钟、Thread
、線程阻塞
、method
解析Java Thread 類方法
-
sleep()
-
suspend()
-
resume()
-
yield()
-
wait()
-
notify()
線程的阻塞
線程的阻塞發(fā)生原因是什么比原?
- 為了解決對
共享存儲區(qū)
的訪問沖突,Java 引入了同步機制
,現(xiàn)在讓我們來考察多個線程對共享資源的訪問,顯然同步機制已經(jīng)不夠了舆驶,因為在任意時刻所要求的資源不一定已經(jīng)準(zhǔn)備好了被訪問,反過來而钞,同一時刻準(zhǔn)備好了的資源也可能不止一個沙廉。為了解決這種情況下的訪問控制問題,Java 引入了對阻塞機制的支持臼节。
什么是線程阻塞撬陵?
- 阻塞指的是暫停一個線程的執(zhí)行以等待某個條件發(fā)生(如某資源就緒),學(xué)過操作系統(tǒng)的同學(xué)對它一定已經(jīng)很熟悉了官疲。Java 提供了大量方法來支持阻塞袱结,下面讓我們逐一分析亮隙。
Thread方法解析
sleep() 方法:
sleep()
允許 指定以毫秒為單位的一段時間作為參數(shù)途凫,它使得線程在指定的時間內(nèi)進入阻塞狀態(tài)是牢,不能得到CPU 時間笛厦,指定的時間一過,線程重新進入可執(zhí)行狀態(tài)员萍。 典型的sleep()
被用在等待某個資源就緒的情形:測試發(fā)現(xiàn)條件不滿足后促王,讓線程阻塞一段時間后重新測試犀盟,直到條件滿足為止。suspend() 和 resume() 方法:兩個方法配套使用蝇狼,
suspend()
使得線程進入阻塞狀態(tài)阅畴,并且不會自動恢復(fù),必須其對應(yīng)的resume()
被調(diào)用迅耘,才能使得線程重新進入可執(zhí)行狀態(tài)贱枣。典型的suspend()
和resume()
被用在等待另一個線程產(chǎn)生的結(jié)果的情形:測試發(fā)現(xiàn)結(jié)果還沒有產(chǎn)生后,讓線程阻塞颤专,另一個線程產(chǎn)生了結(jié)果后纽哥,調(diào)用resume()
使其恢復(fù)。yield() 方法:
yield()
使得線程放棄當(dāng)前分得的 CPU 時間栖秕,但是不使線程阻塞春塌,即線程仍處于可執(zhí)行狀態(tài),隨時可能再次分得 CPU 時間。調(diào)用yield()
的效果等價于調(diào)度程序認(rèn)為該線程已執(zhí)行了足夠的時間從而轉(zhuǎn)到另一個線程.wait() 和 notify() 方法:兩個方法配套使用只壳,
wait()
使得線程進入阻塞狀態(tài)俏拱,它有兩種形式,一種允許 指定以毫秒為單位的一段時間作為參數(shù)吼句,另一種沒有參數(shù)彰触,前者當(dāng)對應(yīng)的notify()
被調(diào)用或者超出指定時間時線程重新進入可執(zhí)行狀態(tài),后者則必須對應(yīng)的notify()
被調(diào)用命辖。
方法概述
首先况毅,前面敘述的所有方法都隸屬于
Thread
類,但是這一對卻直接隸屬于Object
類尔艇,也就是說尔许,所有對象都擁有這一對方法。初看起來這十分不可思議终娃,但是實際上卻是很自然的味廊,因為這一對方法阻塞時要釋放占用的鎖,而鎖是任何對象都具有的棠耕,調(diào)用任意對象的wait()
方法導(dǎo)致線程阻塞余佛,并且該對象上的鎖被釋放。而調(diào)用 任意對象的notify()
方法則導(dǎo)致因調(diào)用該對象的wait()
方法而阻塞的線程中隨機選擇的一個解除阻塞(但要等到獲得鎖后才真正可執(zhí)行)窍荧。其次辉巡,前面敘述的所有方法都可在任何位置調(diào)用,但是這一對方法卻必須在
synchronized
方法或塊中調(diào)用蕊退,理由也很簡單郊楣,只有在synchronized
方法或塊中當(dāng)前線程才占有鎖,才有鎖可以釋放瓤荔。同樣的道理净蚤,調(diào)用這一對方法的對象上的鎖必須為當(dāng)前線程所擁有,這樣才有鎖可以釋放输硝。因此今瀑,這一對方法調(diào)用必須放置在這樣的synchronized
方法或塊中,該方法或塊的上鎖對象就是調(diào)用這一對方法的對象点把。若不滿足這一條件橘荠,則程序雖然仍能編譯,但在運行時會出現(xiàn)IllegalMonitorStateException
異常愉粤。
關(guān)于 wait() 和 notify() 方法最后再說明兩點:
調(diào)用
notify()
方法導(dǎo)致解除阻塞的線程是從因調(diào)用該對象的wait()
方法而阻塞的線程中隨機選取的砾医,我們無法預(yù)料哪一個線程將會被選擇,所以編程時要特別小心衣厘,避免因這種不確定性而產(chǎn)生問題如蚜。除了
notify()
压恒,還有一個方法notifyAll()
也可起到類似作用,唯一的區(qū)別在于错邦,調(diào)用 notifyAll() 方法將把因調(diào)用該對象的 wait() 方法而阻塞的所有線程一次性全部解除阻塞探赫。當(dāng)然,只有獲得鎖的那一個線程才能進入可執(zhí)行狀態(tài)撬呢。