上下文切換
? 上下文切換在某種程度上可以被看作多個(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í):
- Thread.sleep()
- Object.wait()/wait(long)
- Thread.yield
- Thread.join
- lockSupport.park()
- 發(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)是吞吐率較小。