多線(xiàn)程編程之上下文切換、活性故障以及調(diào)度策略的理解

上下文切換

? 上下文切換在某種程度上可以被看作多個(gè)線(xiàn)程共享同一個(gè)處理器的產(chǎn)物。

? 概念: 對(duì)于單核CPU來(lái)說(shuō)(對(duì)于多核CPU,此處就理解為一個(gè)核),CPU在一個(gè)時(shí)刻只能運(yùn)行一個(gè)線(xiàn)程,當(dāng)在運(yùn)行一個(gè)線(xiàn)程的過(guò)程中轉(zhuǎn)去運(yùn)行另外一個(gè)線(xiàn)程,這個(gè)叫做線(xiàn)程上下文切換(對(duì)于進(jìn)程也是類(lèi)似)

? 即使是單核CPU也支持多線(xiàn)程執(zhí)行代碼,CPU通過(guò)給每個(gè)線(xiàn)程分配CPU時(shí)間片來(lái)實(shí)現(xiàn)這個(gè)機(jī)制。時(shí)間片是CPU分配給各個(gè)線(xiàn)程的時(shí)間,因?yàn)闀r(shí)間片非常短,所以CPU通過(guò)不停地切換線(xiàn)程執(zhí)行,讓我們感覺(jué)多個(gè)線(xiàn)程時(shí)同時(shí)執(zhí)行的,時(shí)間片一般是幾十毫秒(ms)。

? CPU通過(guò)時(shí)間片分配算法來(lái)循環(huán)執(zhí)行任務(wù),當(dāng)前任務(wù)執(zhí)行一個(gè)時(shí)間片后會(huì)切換到下一個(gè)任務(wù)。但是,在切換前會(huì)保存上一個(gè)任務(wù)的狀態(tài),以便下次切換回這個(gè)任務(wù)時(shí),可以再次加載這個(gè)任務(wù)的狀態(tài),從任務(wù)保存到再加載的過(guò)程就是一次上下文切換。

自發(fā)性上下文切換:

線(xiàn)程在執(zhí)行以下任一一個(gè)方法時(shí):

  1. Thread.sleep()
  2. Object.wait()/wait(long)
  3. Thread.yield
  4. Thread.join
  5. lockSupport.park()
  6. 發(fā)起IO操作或等待其他線(xiàn)程持有的鎖。

非自發(fā)性:

是指線(xiàn)程由于線(xiàn)程調(diào)度器的原因被迫退出,時(shí)間片用完或者被一個(gè)優(yōu)先級(jí)更高的線(xiàn)程運(yùn)行。

如何減少上下文切換

? 既然上下文切換會(huì)導(dǎo)致額外的開(kāi)銷(xiāo),因此減少上下文切換次數(shù)便可以提高多線(xiàn)程程序的運(yùn)行效率。減少上下文切換的方法有無(wú)鎖并發(fā)編程、CAS算法、使用最少線(xiàn)程和使用協(xié)程。

  • 無(wú)鎖并發(fā)編程。多線(xiàn)程競(jìng)爭(zhēng)時(shí),會(huì)引起上下文切換,所以多線(xiàn)程處理數(shù)據(jù)時(shí),可以用一些辦法來(lái)避免使用鎖,如將數(shù)據(jù)的ID按照Hash取模分段,不同的線(xiàn)程處理不同段的數(shù)據(jù)
  • CAS算法。Java的Atomic包使用CAS算法來(lái)更新數(shù)據(jù),而不需要加鎖
  • 使用最少線(xiàn)程。避免創(chuàng)建不需要的線(xiàn)程,比如任務(wù)很少,但是創(chuàng)建了很多線(xiàn)程來(lái)處理,這樣會(huì)造成大量線(xiàn)程都處于等待狀態(tài)
  • 協(xié)程。在單線(xiàn)程里實(shí)現(xiàn)多任務(wù)的調(diào)度,并在單線(xiàn)程里維持多個(gè)任務(wù)間的切換.

線(xiàn)程的活性故障

? 線(xiàn)程是為任務(wù)而生的。因此,理想情況下我們希望線(xiàn)程一直處于 RUNNABLE狀態(tài)。 顯然,事實(shí)并非如此:導(dǎo)致-一個(gè)線(xiàn)程可能處于非RUNNABLE狀態(tài)的因素除了資源(主要 是處理器資源有限而導(dǎo)致的上下文切換)限制之外,還有程序自身的錯(cuò)誤和缺陷。這些由于資源稀缺性或者程序自身的問(wèn)題和缺陷導(dǎo)致線(xiàn)程一直處于非 RUNNABLE狀態(tài),或者線(xiàn)程 雖然處于RUNNABLE狀態(tài)但是其要執(zhí)行的任務(wù)卻一直 無(wú)法進(jìn)展的現(xiàn)象就被稱(chēng)為線(xiàn)程活性 故障(Liveness Failure )。

常見(jiàn)的活性故障包括以下幾種。

? 死鎖( Deadlock)。死鎖好比鷸蚌相爭(zhēng)故事中的情形:鷸啄住蚌的肉,蚌夾住鷸 的嘴。鷸對(duì)蚌說(shuō):“ 你先放開(kāi)我的嘴我就不啄你的肉?!倍鰧?duì)鷸說(shuō):“ 你先放開(kāi) 我的肉我就不夾你的嘴?!庇谑亲詈笳l(shuí)也不放開(kāi)誰(shuí)!死鎖產(chǎn)生的典型場(chǎng)景是一個(gè)線(xiàn) 程X持有資源A的時(shí)候等待另外一個(gè)線(xiàn)程釋放資源B,而另外一個(gè)線(xiàn)程Y在持 有資源B的時(shí)候卻等待線(xiàn)程X釋放資源A。死鎖的外在表現(xiàn)是當(dāng)事線(xiàn)程的生命周 期狀態(tài)永遠(yuǎn)處于非RUNNABLE狀態(tài)而使其任務(wù)一直無(wú)法進(jìn)展。

? ●鎖死(Lockout)。鎖死就好比睡美人的故事中睡美人醒來(lái)的前提是她要得到王子 的親吻,但是如果王子無(wú)法親吻她(比如王子“掛了”....,那么睡美人將一 直沉睡!

●活鎖(Livelock)。活鎖好比小貓?jiān)噲D咬自己的尾巴,雖然它總是追著自己的尾巴咬,但卻始終無(wú)法咬到?;铈i的外在表現(xiàn)是線(xiàn)程可能處于RUNNABLE狀態(tài), 但是線(xiàn)程所要執(zhí)行的任務(wù)卻絲毫沒(méi)有進(jìn)展,即線(xiàn)程可能一直在 做無(wú)用功。

? ●饑餓(Starvation)。饑餓好比母鳥(niǎo)給雛鳥(niǎo)喂食的情形,健壯的雛鳥(niǎo)總是搶先從母 鳥(niǎo)的嘴中搶到食物,從而導(dǎo)致那此弱小的雛鳥(niǎo)總是挨餓。饑餓就是線(xiàn)程因無(wú)法教prton的可執(zhí)行文件為: Windows安景裝5yem2perfmon.exe。

調(diào)度策略

? 非公平調(diào)度策略是我們多數(shù)情況下的首選資源調(diào)度策略。其優(yōu)點(diǎn)是吞吐率較大; 缺點(diǎn)是資源申請(qǐng)者申請(qǐng)資源所需的時(shí)間偏差可能較大,并可能導(dǎo)致饑餓現(xiàn)象。公 平調(diào)度策略適合在資源的持有線(xiàn)程占用資源的時(shí)間相對(duì)長(zhǎng)或資源的平均申請(qǐng)時(shí)間 間隔相對(duì)長(zhǎng)的情況下,或者對(duì)資源申請(qǐng)所需的時(shí)間偏差有所要求的情況下使用。 其優(yōu)點(diǎn)是線(xiàn)程申請(qǐng)資源所需的時(shí)間偏差較小,并且不會(huì)導(dǎo)致饑餓現(xiàn)象;其缺點(diǎn)是吞吐率較小。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容