full outer join 与full join的区别_sleep、yield、join都是干啥的? sleep与wait有啥区别?中篇[十五]...
點(diǎn)擊上方?“?布衣碼農(nóng)?”?,免費(fèi)訂閱~選擇“?設(shè)為星標(biāo)?”,第一時(shí)間免費(fèi)獲得更新~
「布衣碼農(nóng)」用不到卻又不得不學(xué)習(xí)了解的底層方法+1。Object中的wait、notify、notifyAll,可以用于線程間的通信,核心原理為借助于監(jiān)視器的入口集與等待集邏輯。通過這三個(gè)方法完成線程在指定鎖(監(jiān)視器)上的等待與喚醒,這三個(gè)方法是以鎖(監(jiān)視器)為中心的通信方法 。除了他們之外,還有用于線程調(diào)度、控制的方法,他們是sleep、yield、join方法,他們也可以用于線程的協(xié)作,他們是圍繞著線程的調(diào)度而來的 。sleep方法
有兩個(gè)版本的sleep方法,看得出來,核心仍舊是native方法。非native方法只是進(jìn)行了參數(shù)校驗(yàn),接著仍舊是調(diào)用的native方法,這個(gè)情形與wait是類似的接下來仔細(xì)看下,native版本的sleep在指定的毫秒數(shù)內(nèi)讓當(dāng)前正在執(zhí)行的線程休眠(暫停執(zhí)行),此操作受到系統(tǒng)計(jì)時(shí)器和調(diào)度程序精度和準(zhǔn)確性的影響。該線程不丟失任何監(jiān)視器的所屬權(quán)。注意:sleep不會(huì)釋放鎖,不會(huì)釋放鎖,不會(huì)釋放鎖!!!可以理解為他進(jìn)入監(jiān)視器這個(gè)房間之后,在這房間里面睡著了。與wait類似的是,sleep也是可中斷方法(從方法簽名可以看得出來,可能拋出InterruptedException),也就是說如果一個(gè)線程正在sleep,如果另外的線程將他中斷(調(diào)用interrupt方法),將會(huì)拋出異常,并且中斷狀態(tài)將會(huì)擦除。所以對(duì)于sleep方法,要么自己醒來,要么被中斷后也會(huì)醒來。對(duì)于sleep始終有一個(gè)超時(shí)時(shí)間的設(shè)置,所以,盡管他是在監(jiān)視器內(nèi)睡著了,但是并不會(huì)導(dǎo)致死鎖,因?yàn)樗K究是要醒來的。如下,線程休眠500毫秒,主線程50毫秒打印一次狀態(tài)ps:sleep方法的調(diào)用結(jié)果為狀態(tài):TIMED_WAITING借助于sleep方法,可以模擬線程的順序執(zhí)行比如下面示例,兩個(gè)階段,第二個(gè)階段將在第一個(gè)階段執(zhí)行之后才會(huì)執(zhí)行package test1;import java.lang.Thread.State;public class T16 {public static void main(String[] args) { //模擬執(zhí)行任務(wù)的第一個(gè)階段的執(zhí)行 Thread stepOne = new Thread(() -> { System.out.println(Thread.currentThread().getName()+" : 第一階段任務(wù)開始執(zhí)行"); try { Thread.sleep(1000); System.out.println(Thread.currentThread().getName()+" : 第一階段任務(wù)執(zhí)行結(jié)束"); } catch (InterruptedException e) { } }, "firstStage"); stepOne.start(); //模擬任務(wù)第二個(gè)階段的執(zhí)行 Thread stepTwo = new Thread(() -> { while (!State.TERMINATED.equals(stepOne.getState())) { try { Thread.sleep(100); System.out.println(Thread.currentThread().getName()+" : 我在等待第一階段任務(wù)執(zhí)行結(jié)束"); } catch (InterruptedException e) { } } System.out.println(Thread.currentThread().getName()+" : 第二階段任務(wù)執(zhí)行結(jié)束"); }, "secondStage"); stepTwo.start(); }}另外,你應(yīng)該已經(jīng)注意到sleep方法都有static修飾,既然是靜態(tài)方法,在Thread中的慣例就是針對(duì)于:當(dāng)前線程,當(dāng)前線程,當(dāng)前線程!yield方法
對(duì)于sleep或者wait方法,他們都將進(jìn)入特定的狀態(tài),伴隨著狀態(tài)的切換,也就意味著等待某些條件的發(fā)生,才能夠繼續(xù),比如條件滿足,或者到時(shí)間等。但是yield方法不涉及這些事情,他針對(duì)的是時(shí)間片的劃分與調(diào)度,所以對(duì)開發(fā)者來說只是臨時(shí)讓一下,讓一下他又不會(huì)死,就只是再等等yield方法將會(huì)暫停當(dāng)前正在執(zhí)行的線程對(duì)象,并執(zhí)行其他線程,他始終都是RUNNABLE狀態(tài)不過要注意,可以認(rèn)為yield只是一種建議性的,如果調(diào)用了yield方法,對(duì)CPU時(shí)間片的分配進(jìn)行了“禮讓”,他仍舊有可能繼續(xù)獲得時(shí)間片,并且繼續(xù)執(zhí)行。所以一次調(diào)用yield 并不一定會(huì)代表肯定會(huì)發(fā)生什么。借助于while循環(huán)以及yield方法,也能一定程度上達(dá)到線程排序等待的效果yield也是靜態(tài)方法,所以,也是針對(duì)于當(dāng)前線程,當(dāng)前線程,當(dāng)前線程。join方法
三個(gè)版本的join方法方法的實(shí)現(xiàn)過程,與wait也是非常類似,下面兩個(gè)版本的方法一個(gè)調(diào)用join(0),一個(gè)參數(shù)校驗(yàn)后,調(diào)用join(millis),所以根本還是單參數(shù)版本的join方法在方法深入介紹前先看個(gè)例子一個(gè)線程,循環(huán)5次,每次sleep 1s,主線程中打印信息從結(jié)果可以看到,主線程總是在線程執(zhí)行之后,才會(huì)執(zhí)行。也就是主線程在等待我們創(chuàng)建的這個(gè)線程結(jié)束,結(jié)束了之后才會(huì)繼續(xù)進(jìn)行如果調(diào)整下順序--->start 與 join的先后順序,再次看下情況,可以發(fā)現(xiàn)順序沒有保障了結(jié)論:主線程main中調(diào)用啟動(dòng)線程(調(diào)用start),然后調(diào)用該線程的join方法,可以達(dá)到主線程等待工作線程運(yùn)行結(jié)束才執(zhí)行的效果,并且join要在start調(diào)用后如何做到的?從上面源代碼可以看得出來,內(nèi)部調(diào)用了wait方法,所以也能明白為啥join也會(huì)拋出InterruptedException了吧主線程main中調(diào)用thread.join()方法,join方法相當(dāng)于join(0),也就是 while (isAlive()) { wait(0); }而這個(gè)wait(0)就相當(dāng)于是this.wait(0),this就是我們自己創(chuàng)建的那個(gè)線程thread,看看方法的簽名是不是有一個(gè)synchronized。isAlive()也是this.isAlive(),也就是如果當(dāng)前線程alive(已經(jīng)啟動(dòng),但是未終止),那么將持續(xù)等待,等待的臨界資源就是我們創(chuàng)建的這個(gè)線程對(duì)象本身。所以這兩行代碼的含義就是:該線程是否還存活?如果存活,調(diào)用join的那個(gè)線程將會(huì)在這個(gè)對(duì)象上進(jìn)行等待(進(jìn)入該線程對(duì)象的等待集)也就是說調(diào)用一個(gè)線程的join方法,就是在這個(gè)線程是等待,這個(gè)線程對(duì)象就是我們的鎖對(duì)象(不要疑惑,Object都可以作為鎖,Thread實(shí)例對(duì)象怎么不可以?)肯定大家很奇怪,既然是等待,wait又不會(huì)自己醒來,那不是出問題了嗎?其實(shí)線程結(jié)束后,會(huì)調(diào)用this.notifyAll,所以主線程main會(huì)被喚醒如果傳遞的參數(shù)不為0,將會(huì)走到下面的分支,會(huì)wait指定時(shí)長(zhǎng),與上面的邏輯一致,只不過是有指定超時(shí)時(shí)長(zhǎng)而已 long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base;手動(dòng)版本的等待結(jié)束只是將join方法換成了同步代碼塊,鎖對(duì)象為那個(gè)線程的實(shí)例對(duì)象thread,調(diào)用他的wait方法從結(jié)果上看,效果一樣(不過此處沒有持續(xù)監(jiān)測(cè)isAlive(),所以一旦主線程醒來,即使線程沒有結(jié)束,也會(huì)繼續(xù),不能百分百確保main肯定等待線程結(jié)束)不過要注意:注釋中有說明,自己不要使用Thread類的實(shí)例對(duì)象作為鎖對(duì)象,如果是現(xiàn)在這種場(chǎng)景,使用join即可為什么?從目前來看,join方法就是以這個(gè)對(duì)象為鎖,如果你自己在使用,又是wait又是notify(notifyAll)的,萬一出現(xiàn)什么隱匿的問題咋辦?所以join方法的原理就是:將指定的Thread實(shí)例對(duì)象作為鎖對(duì)象,在其上進(jìn)行同步,只要那個(gè)線程還活著,那么就會(huì)持續(xù)等待(或者有限時(shí)長(zhǎng))。線程終止之后會(huì)調(diào)用自身this.notifyAll,以通知在其上等待的線程。簡(jiǎn)單說,只要他活著大家就都等著, 他死了會(huì)通知,所以效果就是在哪里調(diào)用了誰的join,哪里就要等待這個(gè)線程結(jié)束,才能繼續(xù)。為什么要在start之后?如上面所示,將join改造成同步代碼塊如下所示,如果這段同步代碼在start方法之前看下結(jié)果,沒有等待指定線程結(jié)束,main主線程就結(jié)束了因?yàn)槿绻€沒有調(diào)用start方法,那么isAlive是false(已開始未結(jié)束),主線程根本就不會(huì)等待,所以繼續(xù)執(zhí)行,然后繼續(xù)到下面的start,然后主線程結(jié)束。所以,為什么join方法一定要在start之前?就是因?yàn)檫@個(gè)isAlive方法的校驗(yàn),你沒有start,isAlive就是false,就不會(huì)同步等待,所以必須要先start,然后才能join小結(jié):對(duì)于join方法,有兩個(gè)關(guān)鍵:調(diào)用的哪個(gè)對(duì)象的join?
在哪里調(diào)用的?
狀態(tài)圖回顧
在回顧下之前狀態(tài)一文中的切換圖,又了解了這幾個(gè)方法后,應(yīng)該對(duì)狀態(tài)切換有了更全面的認(rèn)識(shí)總結(jié)
對(duì)于yield方法,比較容易理解,只是簡(jiǎn)單地對(duì)于CPU時(shí)間片的“禮讓”,除非循環(huán)yield,否則一次yield,可能下次該線程仍舊可能會(huì)搶占到CPU時(shí)間片,可能方法調(diào)用和不調(diào)用沒差別。sleep是靜態(tài)方法,針對(duì)當(dāng)前線程,進(jìn)入休眠狀態(tài),兩個(gè)版本的sleep方法始終有時(shí)間參數(shù),所以必然會(huì)在指定的時(shí)間內(nèi)蘇醒,他也不會(huì)釋放鎖,當(dāng)然,sleep方法的調(diào)用不是必須在同步方法(同步代碼塊)內(nèi)。join是實(shí)例方法,表示等待誰,是用于線程順序的調(diào)度方法,可以做到一個(gè)線程等待另外一個(gè)線程,join有三個(gè)版本,指定超時(shí)時(shí)間或者持續(xù)等待直到目標(biāo)線程執(zhí)行結(jié)束,join也無需在同步方法(同步代碼塊)內(nèi)。sleep和join都是可中斷方法,被其他線程中斷時(shí),都會(huì)拋出InterruptedException異常,并且會(huì)醒來join方法底層依賴wait,我們對(duì)比下wait與sleep?wait和sleep都會(huì)使線程進(jìn)入阻塞狀態(tài),都是可中斷方法,被中斷后都會(huì)拋出異常
wait是Object的方法,sleep是Thread的方法
wait必須在同步中執(zhí)行,sleep不需要(join底層依賴wait,但是不需要在同步中,因?yàn)閖oin方法就是synchronized的)
wait會(huì)釋放鎖,sleep不會(huì)釋放鎖
wait(無超時(shí)設(shè)置的版本)會(huì)持續(xù)阻塞,必須等待喚醒,而sleep必然有超時(shí),所以一定會(huì)自己醒來
wait 實(shí)例方法(Object),在對(duì)象上調(diào)用,表示在其上等待;sleep靜態(tài)方法,當(dāng)前線程??
··················END··················
注:非技術(shù)講解配圖均來源于網(wǎng)絡(luò)
期待分享
如果對(duì)你有用
可以點(diǎn)個(gè)?「在看」?或者分享到?「?朋友圈?」?哦
你「在看」嗎??↓↓
總結(jié)
以上是生活随笔為你收集整理的full outer join 与full join的区别_sleep、yield、join都是干啥的? sleep与wait有啥区别?中篇[十五]...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python高阶函数、map reduc
- 下一篇: JAVA入门级教学之(类之间究竟有哪几种