溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

代碼中的Thread.sleep(0) 有什么意義呢

發(fā)布時(shí)間:2021-12-17 14:49:51 來源:億速云 閱讀:384 作者:柒染 欄目:云計(jì)算

這篇文章給大家介紹代碼中的Thread.sleep(0) 有什么意義呢,內(nèi)容非常詳細(xì),感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

你以為你是一個(gè)高級(jí)工程師,實(shí)際上也就只是會(huì)用幾個(gè)框架的API而已!最近代碼中出現(xiàn)了一個(gè) Thread.sleep(0),引起了大家的注意。有人說是寫錯(cuò)了,有人說是沒意義可以刪掉!是這樣嗎?通過本文希望大家看完后有更大的收獲!

我們知道 Thread.sleep() 方法能讓線程休眠一段時(shí)間,但是當(dāng)這個(gè)參數(shù)為0,還有意義嗎?假設(shè)現(xiàn)在的時(shí)間是 2018-10-16 18:00:00.000,當(dāng)我調(diào)用一下Thread.sleep(0)后,在2018-10-16 18:00:00.001這個(gè)時(shí)間當(dāng)前休眠的這個(gè)線程會(huì)被喚醒嗎?

要回答這個(gè)問題,我們先要看 Thread.sleep() 到底做了什么?既然是 Sleep 0 毫秒,那到底休眠了嗎?

代碼中的Thread.sleep(0) 有什么意義呢

我們知道處理器是一個(gè)操作系統(tǒng)執(zhí)行任務(wù)的工具,線程是一個(gè)操作系統(tǒng)執(zhí)行任務(wù)的基本單位,處理器的數(shù)量決定了不可能所有線程都能同時(shí)得到執(zhí)行。這就需要通過某種算法來進(jìn)行任務(wù)調(diào)度。Unix系統(tǒng)使用的是時(shí)間片算法,而Windows 是一個(gè)搶占式的多任務(wù)操作系統(tǒng)。

關(guān)于搶占式,維基百科有下面的定義:

In computing, preemption is the act of temporarily interrupting a task being carried out by a computer system, without requiring its cooperation, and with the intention of resuming the task at a later time. Such a change is known as a context switch. It is normally carried out by a privileged task or part of the system known as a preemptive scheduler, which has the power to preempt, or interrupt, and later resume, other tasks in the system.

大致的意思是說:

線程是根據(jù)其優(yōu)先級(jí)而調(diào)度執(zhí)行的。 即使線程正在運(yùn)行時(shí)中執(zhí)行,所有線程都是由操作系統(tǒng)分配處理器時(shí)間片的。 用于確定線程執(zhí)行順序的調(diào)度算法的詳細(xì)情況隨每個(gè)操作系統(tǒng)的不同而不同。

在某些操作系統(tǒng)下,具有最高優(yōu)先級(jí)(相對于可執(zhí)行線程而言)的線程經(jīng)過調(diào)度后總是首先運(yùn)行。 如果具有相同優(yōu)先級(jí)的多個(gè)線程都可用,則計(jì)劃程序?qū)⒈闅v處于該優(yōu)先級(jí)的線程,并為每個(gè)線程提供一個(gè)固定的時(shí)間片(段)來執(zhí)行。 只要具有較高優(yōu)先級(jí)的線程可以運(yùn)行,具有較低優(yōu)先級(jí)的線程就不會(huì)執(zhí)行。 如果在給定的優(yōu)先級(jí)上不再有可運(yùn)行的線程,則計(jì)劃程序?qū)⒁频较乱粋€(gè)較低的優(yōu)先級(jí)并在該優(yōu)先級(jí)上調(diào)度線程以執(zhí)行。 如果此時(shí)具有較高優(yōu)先級(jí)的線程可以運(yùn)行,則具有較低優(yōu)先級(jí)的線程將被搶先,并允許具有較高優(yōu)先級(jí)的線程再次執(zhí)行。 除此之外,當(dāng)應(yīng)用程序的用戶界面在前臺(tái)和后臺(tái)之間移動(dòng)時(shí),操作系統(tǒng)還可以動(dòng)態(tài)調(diào)整線程優(yōu)先級(jí)。 其他操作系統(tǒng)可以選擇使用不同的調(diào)度算法。

Windows 除了會(huì)在前后臺(tái)切換的時(shí)候調(diào)整優(yōu)先級(jí)還會(huì)為 I/O 操作動(dòng)態(tài)提升優(yōu)先級(jí),或者使用 “饑渴” 的時(shí)間片分配策略來動(dòng)態(tài)調(diào)整,如果有線程一直渴望得到時(shí)間片但是很長時(shí)間都沒有獲得時(shí)間片,Windows 就會(huì)臨時(shí)將這個(gè)線程的優(yōu)先級(jí)提高,并一次分配給2倍的時(shí)間片來執(zhí)行,當(dāng)用完2倍的時(shí)間片后,優(yōu)先級(jí)又會(huì)恢復(fù)到之前的水平。

在時(shí)間片算法中,所有的進(jìn)程排成一個(gè)隊(duì)列。操作系統(tǒng)按照他們的順序,給每個(gè)進(jìn)程分配一段時(shí)間,即該進(jìn)程允許運(yùn)行的時(shí)間。如果在時(shí)間片結(jié)束時(shí)進(jìn)程還在運(yùn)行,則CPU將被剝奪并分配給另一個(gè)進(jìn)程。如果進(jìn)程在時(shí)間片結(jié)束前阻塞或結(jié)束,則CPU當(dāng)即進(jìn)行切換。調(diào)度程序所要做的就是維護(hù)一張就緒進(jìn)程列表,當(dāng)進(jìn)程用完它的時(shí)間片后,它被移到隊(duì)列的末尾。

我們用分蛋糕的場景來描述這兩種算法。假設(shè)有源源不斷的蛋糕(源源不斷的時(shí)間),一副刀叉(一個(gè)CPU),10個(gè)等待吃蛋糕的人(10 個(gè)進(jìn)程)。

如果是Unix操作系統(tǒng)來負(fù)責(zé)分蛋糕,那么他會(huì)這樣定規(guī)矩:每個(gè)人上來吃 1 分鐘,時(shí)間到了換下一個(gè)。最后一個(gè)人吃完了就再從頭開始。于是,不管這10個(gè)人是不是優(yōu)先級(jí)不同、饑餓程度不同、飯量不同,每個(gè)人上來的時(shí)候都可以吃 1 分鐘。當(dāng)然,如果有人本來不太餓,或者飯量小,吃了30秒鐘之后就吃飽了,那么他可以跟操作系統(tǒng)說:我已經(jīng)吃飽了(掛起)。于是操作系統(tǒng)就會(huì)讓下一個(gè)人接著來。

如果是 Windows 操作系統(tǒng)來負(fù)責(zé)分蛋糕的,那么場面就很有意思了。他會(huì)這樣定規(guī)矩:我會(huì)根據(jù)你們的優(yōu)先級(jí)、饑餓程度去給你們每個(gè)人計(jì)算一個(gè)優(yōu)先級(jí)。優(yōu)先級(jí)最高的那個(gè)人,可以上來吃蛋糕——吃到你不想吃為止。等這個(gè)人吃完了,我再重新根據(jù)優(yōu)先級(jí)、饑餓程度來計(jì)算每個(gè)人的優(yōu)先級(jí),然后再分給優(yōu)先級(jí)最高的那個(gè)人。

這樣看來,這個(gè)場面就有意思了??赡苡行┤耸瞧罬M,因此具有高優(yōu)先級(jí),于是她就可以經(jīng)常來吃蛋糕??赡芰硗庖粋€(gè)人是個(gè)猥瑣男,所以優(yōu)先級(jí)特別低,于是好半天了才輪到他一次(因?yàn)殡S著時(shí)間的推移,他會(huì)越來越饑餓,因此算出來的總優(yōu)先級(jí)就會(huì)越來越高,因此總有一天會(huì)輪到他的)。而且,如果一不小心讓一個(gè)大胖子得到了刀叉,因?yàn)樗埩看?,可能他?huì)霸占著蛋糕連續(xù)吃很久很久,導(dǎo)致旁邊的人在那里咽口水。

而且,還可能會(huì)有這種情況出現(xiàn):操作系統(tǒng)現(xiàn)在計(jì)算出來的結(jié)果,5號(hào)漂亮MM總優(yōu)先級(jí)最高,而且高出別人一大截。因此就叫5號(hào)來吃蛋糕。5號(hào)吃了一小會(huì)兒,覺得沒那么餓了,于是說“我不吃了”(掛起)。因此操作系統(tǒng)就會(huì)重新計(jì)算所有人的優(yōu)先級(jí)。因?yàn)?號(hào)剛剛吃過,因此她的饑餓程度變小了,于是總優(yōu)先級(jí)變小了;而其他人因?yàn)槎嗟攘艘粫?huì)兒,饑餓程度都變大了,所以總優(yōu)先級(jí)也變大了。不過這時(shí)候仍然有可能5號(hào)的優(yōu)先級(jí)比別的都高,只不過現(xiàn)在只比其他的高一點(diǎn)點(diǎn)——但她仍然是總優(yōu)先級(jí)最高的啊。因此操作系統(tǒng)就會(huì)說:5號(hào)MM上來吃蛋糕……(5號(hào)MM心里郁悶,這不剛吃過嘛……人家要減肥……誰叫你長那么漂亮,獲得了那么高的優(yōu)先級(jí))。

那么,Thread.sleep 函數(shù)是干嗎的呢?

還用剛才的分蛋糕的場景來描述。上面的場景里面,5號(hào)MM在吃了一次蛋糕之后,覺得已經(jīng)有8分飽了,她覺得在未來的半個(gè)小時(shí)之內(nèi)都不想再來吃蛋糕了,那么她就會(huì)跟操作系統(tǒng)說:在未來的半個(gè)小時(shí)之內(nèi)不要再叫我上來吃蛋糕了。這樣,操作系統(tǒng)在隨后的半個(gè)小時(shí)里面重新計(jì)算所有人總優(yōu)先級(jí)的時(shí)候,就會(huì)忽略5號(hào)MM。sleep函數(shù)就是干這事的,他告訴操作系統(tǒng)“在未來的多少毫秒內(nèi)我不參與CPU競爭”。

現(xiàn)在我們再來看文章開頭那個(gè)問題。執(zhí)行 Thread.sleep(0) 后,當(dāng)前線程不一定會(huì)被喚醒,雖然休眠了0秒,但是執(zhí)行 sleep 方法后,不僅會(huì)休眠,還會(huì)讓 CPU 重新分配。因此,Thread.Sleep(0)的作用,就是“觸發(fā)操作系統(tǒng)立刻重新進(jìn)行一次CPU競爭”。競爭的結(jié)果也許是當(dāng)前線程仍然獲得CPU控制權(quán),也許會(huì)換成別的線程獲得CPU控制權(quán)。這也是我們在大循環(huán)里面經(jīng)常會(huì)寫一句Thread.Sleep(0) ,因?yàn)檫@樣就給了其他線程獲得CPU控制權(quán)的權(quán)力,這樣一些功能就不會(huì)假死在那里。

末了說明一下,雖然上面提到說“除非它自己放棄使用 CPU ,否則將完全霸占 CPU”,但這個(gè)行為仍然是受到制約的——操作系統(tǒng)會(huì)監(jiān)控你霸占CPU的情況,如果發(fā)現(xiàn)某個(gè)線程長時(shí)間霸占CPU,會(huì)強(qiáng)制使這個(gè)線程掛起,因此在實(shí)際上不會(huì)出現(xiàn)“一個(gè)線程一直霸占著 CPU 不放”的情況。至于我們的大循環(huán)造成程序假死,并不是因?yàn)檫@個(gè)線程一直在霸占著CPU。實(shí)際上在這段時(shí)間操作系統(tǒng)已經(jīng)進(jìn)行過多次CPU競爭了,只不過其他線程在獲得CPU控制權(quán)之后很短時(shí)間內(nèi)馬上就退出了,于是就又輪到了這個(gè)線程繼續(xù)執(zhí)行循環(huán),于是就又用了很久才被操作系統(tǒng)強(qiáng)制掛起。因此反應(yīng)到程序上,看起來就好像這個(gè)線程一直在霸占著CPU一樣。

關(guān)于代碼中的Thread.sleep(0) 有什么意義呢就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI