上下文切換
? 上下文切換在某種程度上可以被看作多個(gè)線程共享同一個(gè)處理器的產(chǎn)物尚粘。
? 概念: 對(duì)于單核CPU來說(對(duì)于多核CPU蝗蛙,此處就理解為一個(gè)核)蝇庭,CPU在一個(gè)時(shí)刻只能運(yùn)行一個(gè)線程,當(dāng)在運(yùn)行一個(gè)線程的過程中轉(zhuǎn)去運(yùn)行另外一個(gè)線程捡硅,這個(gè)叫做線程上下文切換(對(duì)于進(jìn)程也是類似)
? 即使是單核CPU也支持多線程執(zhí)行代碼哮内,CPU通過給每個(gè)線程分配CPU時(shí)間片來實(shí)現(xiàn)這個(gè)機(jī)制。時(shí)間片是CPU分配給各個(gè)線程的時(shí)間壮韭,因?yàn)闀r(shí)間片非常短北发,所以CPU通過不停地切換線程執(zhí)行,讓我們感覺多個(gè)線程時(shí)同時(shí)執(zhí)行的喷屋,時(shí)間片一般是幾十毫秒(ms)琳拨。
? CPU通過時(shí)間片分配算法來循環(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ù)保存到再加載的過程就是一次上下文切換。
自發(fā)性上下文切換:
線程在執(zhí)行以下任一一個(gè)方法時(shí):
- Thread.sleep()
- Object.wait()/wait(long)
- Thread.yield
- Thread.join
- lockSupport.park()
- 發(fā)起IO操作或等待其他線程持有的鎖驳棱。
非自發(fā)性:
是指線程由于線程調(diào)度器的原因被迫退出焰盗,時(shí)間片用完或者被一個(gè)優(yōu)先級(jí)更高的線程運(yùn)行叭喜。
如何減少上下文切換
? 既然上下文切換會(huì)導(dǎo)致額外的開銷,因此減少上下文切換次數(shù)便可以提高多線程程序的運(yùn)行效率挚躯。減少上下文切換的方法有無鎖并發(fā)編程乳规、CAS算法形葬、使用最少線程和使用協(xié)程。
- 無鎖并發(fā)編程暮的。多線程競(jìng)爭(zhēng)時(shí)笙以,會(huì)引起上下文切換,所以多線程處理數(shù)據(jù)時(shí)冻辩,可以用一些辦法來避免使用鎖猖腕,如將數(shù)據(jù)的ID按照Hash取模分段拆祈,不同的線程處理不同段的數(shù)據(jù)
- CAS算法。Java的Atomic包使用CAS算法來更新數(shù)據(jù)倘感,而不需要加鎖
- 使用最少線程放坏。避免創(chuàng)建不需要的線程,比如任務(wù)很少老玛,但是創(chuàng)建了很多線程來處理淤年,這樣會(huì)造成大量線程都處于等待狀態(tài)
- 協(xié)程。在單線程里實(shí)現(xiàn)多任務(wù)的調(diào)度蜡豹,并在單線程里維持多個(gè)任務(wù)間的切換.
線程的活性故障
? 線程是為任務(wù)而生的麸粮。因此,理想情況下我們希望線程一直處于 RUNNABLE狀態(tài)镜廉。 顯然弄诲,事實(shí)并非如此:導(dǎo)致-一個(gè)線程可能處于非RUNNABLE狀態(tài)的因素除了資源(主要 是處理器資源有限而導(dǎo)致的上下文切換)限制之外,還有程序自身的錯(cuò)誤和缺陷桨吊。這些由于資源稀缺性或者程序自身的問題和缺陷導(dǎo)致線程一直處于非 RUNNABLE狀態(tài)威根,或者線程 雖然處于RUNNABLE狀態(tài)但是其要執(zhí)行的任務(wù)卻一直 無法進(jìn)展的現(xiàn)象就被稱為線程活性 故障(Liveness Failure )。
常見的活性故障包括以下幾種视乐。
? 死鎖( Deadlock)洛搀。死鎖好比鷸蚌相爭(zhēng)故事中的情形:鷸啄住蚌的肉,蚌夾住鷸 的嘴佑淀。鷸對(duì)蚌說:“ 你先放開我的嘴我就不啄你的肉∩烊校”而蚌對(duì)鷸說:“ 你先放開 我的肉我就不夾你的嘴∨趼”于是最后誰也不放開誰!死鎖產(chǎn)生的典型場(chǎng)景是一個(gè)線 程X持有資源A的時(shí)候等待另外一個(gè)線程釋放資源B,而另外一個(gè)線程Y在持 有資源B的時(shí)候卻等待線程X釋放資源A。死鎖的外在表現(xiàn)是當(dāng)事線程的生命周 期狀態(tài)永遠(yuǎn)處于非RUNNABLE狀態(tài)而使其任務(wù)一直無法進(jìn)展碉哑。
? ●鎖死(Lockout)挚币。鎖死就好比睡美人的故事中睡美人醒來的前提是她要得到王子 的親吻,但是如果王子無法親吻她(比如王子“掛了”....扣典,那么睡美人將一 直沉睡!
●活鎖(Livelock)〉颜常活鎖好比小貓?jiān)噲D咬自己的尾巴,雖然它總是追著自己的尾巴咬,但卻始終無法咬到薪前∪笈活鎖的外在表現(xiàn)是線程可能處于RUNNABLE狀態(tài), 但是線程所要執(zhí)行的任務(wù)卻絲毫沒有進(jìn)展序六,即線程可能一直在 做無用功。
? ●饑餓(Starvation)例诀。饑餓好比母鳥給雛鳥喂食的情形,健壯的雛鳥總是搶先從母 鳥的嘴中搶到食物拱她,從而導(dǎo)致那此弱小的雛鳥總是挨餓扔罪。饑餓就是線程因無法教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)度策略適合在資源的持有線程占用資源的時(shí)間相對(duì)長(zhǎng)或資源的平均申請(qǐng)時(shí)間 間隔相對(duì)長(zhǎng)的情況下辜腺,或者對(duì)資源申請(qǐng)所需的時(shí)間偏差有所要求的情況下使用休建。 其優(yōu)點(diǎn)是線程申請(qǐng)資源所需的時(shí)間偏差較小评疗,并且不會(huì)導(dǎo)致饑餓現(xiàn)象;其缺點(diǎn)是吞吐率較小。