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