哪些操作導(dǎo)致了上下文切換

在并發(fā)程序中,并不是啟動(dòng)更多的線程就能讓程序最大限度地并發(fā)執(zhí)行席怪。線程數(shù)量設(shè)置太 小应闯,會(huì)導(dǎo)致程序不能充分地利用系統(tǒng)資源;線程數(shù)量設(shè)置太大挂捻,又可能帶來(lái)資源的過(guò)度競(jìng)爭(zhēng)碉纺,導(dǎo)致上下文切換帶來(lái)額外的系統(tǒng)開銷。

初識(shí)上下文切換
其實(shí)在單個(gè)處理器的時(shí)期刻撒,操作系統(tǒng)就能處理多線程并發(fā)任務(wù)骨田。處理器給每個(gè)線程分配 CPU 時(shí)間片(Time Slice),線程在分配獲得的時(shí)間片內(nèi)執(zhí)行任務(wù)疫赎。

CPU 時(shí)間片是 CPU 分配給每個(gè)線程執(zhí)行的時(shí)間段盛撑,一般為幾十毫秒。在這么短的時(shí)間內(nèi)線程互相切換捧搞,根本感覺不到抵卫,所以看上去就好像是同時(shí)進(jìn)行的一樣。

時(shí)間片決定了一個(gè)線程可以連續(xù)占用處理器運(yùn)行的時(shí)長(zhǎng)胎撇。當(dāng)一個(gè)線程的時(shí)間片用完了介粘,或者因自身原因被迫暫停運(yùn)行了,這個(gè)時(shí)候晚树,另外一個(gè)線程(可以是同一個(gè)線程或者其它進(jìn)程的線程)就會(huì)被操作系統(tǒng)選中姻采,來(lái)占用處理器。這種一個(gè)線程被暫停剝奪使用權(quán)爵憎,另外一個(gè)線程被選中開始或者繼續(xù)運(yùn)行的過(guò)程就叫做上下文切換(Context Switch)慨亲。

具體來(lái)說(shuō),一個(gè)線程被剝奪處理器的使用權(quán)而被暫停運(yùn)行宝鼓,就是“切出”刑棵;一個(gè)線程被選中占用處理器開始或者繼續(xù)運(yùn)行,就是“切入”愚铡。在這種切出切入的過(guò)程中蛉签,操作系統(tǒng)需要保存和恢復(fù)相應(yīng)的進(jìn)度信息胡陪,這個(gè)進(jìn)度信息就是“上下文”了。

那上下文都包括哪些內(nèi)容呢碍舍?具體來(lái)說(shuō)柠座,它包括了寄存器的存儲(chǔ)內(nèi)容以及程序計(jì)數(shù)器存儲(chǔ)的指令內(nèi)容。CPU 寄存器負(fù)責(zé)存儲(chǔ)已經(jīng)片橡、正在和將要執(zhí)行的任務(wù)妈经,程序計(jì)數(shù)器負(fù)責(zé)存儲(chǔ)CPU 正在執(zhí)行的指令位置以及即將執(zhí)行的下一條指令的位置。

在當(dāng)前 CPU 數(shù)量遠(yuǎn)遠(yuǎn)不止一個(gè)的情況下捧书,操作系統(tǒng)將 CPU輪流分配給線程任務(wù)狂塘,此時(shí)的上下文切換就變得更加頻繁了,并且存在跨 CPU 上下文切換鳄厌,比起單核上下文切換,跨核切換更加昂貴妈踊。

多線程上下文切換誘因
在操作系統(tǒng)中了嚎,上下文切換的類型還可以分為進(jìn)程間的上下文切換和線程間的上下文切換。而在多線程編程中廊营,我們主要面對(duì)的就是線程間的上下文切換導(dǎo)致的性能問(wèn)題歪泳,下面我們就重點(diǎn)看看究竟是什么原因?qū)е铝硕嗑€程的上下文切換。開始之前露筒,先看下 Java 線程的生命周期狀態(tài)呐伞。

線程主要有“新建”(NEW)、“就緒”(RUNNABLE)慎式、“運(yùn)行”(RUNNING)伶氢、“阻塞”(BLOCKED)、“死亡”(DEAD)五種狀態(tài)瘪吏。

在這個(gè)運(yùn)行過(guò)程中癣防,線程由 RUNNABLE 轉(zhuǎn)為非RUNNABLE 的過(guò)程就是線程上下文切換。一個(gè)線程的狀態(tài)由 RUNNING 轉(zhuǎn)為 BLOCKED 掌眠,再由BLOCKED 轉(zhuǎn)為 RUNNABLE 蕾盯,然后再被調(diào)度器選中執(zhí)行,這就是一個(gè)上下文切換的過(guò)程蓝丙。

當(dāng)一個(gè)線程從 RUNNING 狀態(tài)轉(zhuǎn)為 BLOCKED 狀態(tài)時(shí)级遭,我們稱為一個(gè)線程的暫停,線程暫停被切出之后渺尘,操作系統(tǒng)會(huì)保存相應(yīng)的上下文挫鸽,以便這個(gè)線程稍后再次進(jìn)入RUNNABLE 狀態(tài)時(shí)能夠在之前執(zhí)行進(jìn)度的基礎(chǔ)上繼續(xù)執(zhí)行。

當(dāng)一個(gè)線程從 BLOCKED 狀態(tài)進(jìn)入到 RUNNABLE 狀態(tài)時(shí)沧烈,我們稱為一個(gè)線程的喚醒掠兄,此時(shí)線程將獲取上次保存的上下文繼續(xù)完成執(zhí)行。

通過(guò)線程的運(yùn)行狀態(tài)以及狀態(tài)間的相互切換,我們可以了解到蚂夕,多線程的上下文切換實(shí)際上就是由多線程兩個(gè)運(yùn)行狀態(tài)的互相切換導(dǎo)致的迅诬。

那么在線程運(yùn)行時(shí),線程狀態(tài)由 RUNNING 轉(zhuǎn)為BLOCKED 或者由 BLOCKED 轉(zhuǎn)為 RUNNABLE婿牍,這又是什么誘發(fā)的呢侈贷?

我們可以分兩種情況來(lái)分析,一種是程序本身觸發(fā)的切換等脂,這種我們稱為自發(fā)性上下文切換俏蛮,另一種是由系統(tǒng)或者虛擬機(jī)誘發(fā)的非自發(fā)性上下文切換。 自發(fā)性上下文切換指線程由 Java 程序調(diào)用導(dǎo)致切出上遥,在多線程編程中搏屑,執(zhí)行調(diào)用以下方法或關(guān)鍵字,常常就會(huì)引發(fā)自發(fā)性上下文切換粉楚。
sleep()
wait()
yield()
join()
park()
synchronized
lock

非自發(fā)性上下文切換指線程由于調(diào)度器的原因被迫切出辣恋。常見的有:線程被分配的時(shí)間片用完,虛擬機(jī)垃圾回收導(dǎo)致或者執(zhí)行優(yōu)先級(jí)的問(wèn)題導(dǎo)致模软。

“虛擬機(jī)垃圾回收為什么會(huì)導(dǎo)致上下文切換”伟骨。在 Java 虛擬機(jī)中,對(duì)象的內(nèi)存都是由虛擬機(jī)中的堆分配的燃异,在程序運(yùn)行過(guò)程中携狭,新的對(duì)象將不斷被創(chuàng)建,如果舊的對(duì)象使用后不進(jìn)行回收回俐,堆內(nèi)存將很快被耗盡逛腿。Java虛擬機(jī)提供了一種回收機(jī)制,對(duì)創(chuàng)建后不再使用的對(duì)象進(jìn)行回收仅颇,從而保證堆內(nèi)存的可持續(xù)性分配鳄逾。而這種垃圾回收機(jī)制的使用有可能會(huì)導(dǎo)致 stop-the-world 事件的發(fā)生,這其實(shí)就是一種線程暫停行為灵莲。

發(fā)現(xiàn)上下文切換
我們總說(shuō)上下文切換會(huì)帶來(lái)系統(tǒng)開銷雕凹,那它帶來(lái)的性能問(wèn)題是不是真有這么糟糕呢?我們又該怎么去監(jiān)測(cè)到上下文切換政冻?上下文切換到底開銷在哪些環(huán)節(jié)枚抵?

串聯(lián)的執(zhí)行速度比并發(fā)的執(zhí)行速度要快。這就是因?yàn)榫€程的上下文切換導(dǎo)致了額外的開銷明场,使用 Synchronized 鎖關(guān)鍵字汽摹,導(dǎo)致了資源競(jìng)爭(zhēng),從而引起了上下文切換苦锨,但即使不使用 Synchronized 鎖關(guān)鍵字逼泣,并發(fā)的執(zhí)行速度也無(wú)法超越串聯(lián)的執(zhí)行速度趴泌,這是因?yàn)槎嗑€程同樣存在著上下文切換。Redis拉庶、NodeJS 的設(shè)計(jì)就很好地體現(xiàn)了單線程串行的優(yōu)勢(shì)嗜憔。

在 Linux 系統(tǒng)下,可以使用 Linux 內(nèi)核提供的 vmstat 命令氏仗,來(lái)監(jiān)視 Java 程序運(yùn)行過(guò)程中系統(tǒng)的上下文切換頻率

如果是監(jiān)視某個(gè)應(yīng)用的上下文切換吉捶,就可以使用 pidstat 命令監(jiān)控指定進(jìn)程的 Context Switch 上下文切換。

由于 Windows 沒(méi)有像 vmstat 這樣的工具皆尔,在 Windows下呐舔,我們可以使用 Process Explorer,來(lái)查看程序執(zhí)行時(shí)慷蠕, 線程間上下文切換的次數(shù)珊拼。

至于系統(tǒng)開銷具體發(fā)生在切換過(guò)程中的哪些具體環(huán)節(jié),總結(jié)如下:
操作系統(tǒng)保存和恢復(fù)上下文流炕;
調(diào)度器進(jìn)行線程調(diào)度杆麸;
處理器高速緩存重新加載;
上下文切換也可能導(dǎo)致整個(gè)高速緩存區(qū)被沖刷浪感,從而帶來(lái)時(shí)間開銷。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末饼问,一起剝皮案震驚了整個(gè)濱河市影兽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌莱革,老刑警劉巖峻堰,帶你破解...
    沈念sama閱讀 223,002評(píng)論 6 519
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異盅视,居然都是意外死亡捐名,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,357評(píng)論 3 400
  • 文/潘曉璐 我一進(jìn)店門闹击,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)镶蹋,“玉大人,你說(shuō)我怎么就攤上這事赏半『毓椋” “怎么了?”我有些...
    開封第一講書人閱讀 169,787評(píng)論 0 365
  • 文/不壞的土叔 我叫張陵断箫,是天一觀的道長(zhǎng)拂酣。 經(jīng)常有香客問(wèn)我,道長(zhǎng)仲义,這世上最難降的妖魔是什么婶熬? 我笑而不...
    開封第一講書人閱讀 60,237評(píng)論 1 300
  • 正文 為了忘掉前任剑勾,我火速辦了婚禮,結(jié)果婚禮上赵颅,老公的妹妹穿的比我還像新娘虽另。我一直安慰自己,他們只是感情好性含,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,237評(píng)論 6 398
  • 文/花漫 我一把揭開白布洲赵。 她就那樣靜靜地躺著,像睡著了一般商蕴。 火紅的嫁衣襯著肌膚如雪叠萍。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,821評(píng)論 1 314
  • 那天绪商,我揣著相機(jī)與錄音苛谷,去河邊找鬼。 笑死格郁,一個(gè)胖子當(dāng)著我的面吹牛腹殿,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播例书,決...
    沈念sama閱讀 41,236評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼锣尉,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了决采?” 一聲冷哼從身側(cè)響起自沧,我...
    開封第一講書人閱讀 40,196評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎树瞭,沒(méi)想到半個(gè)月后拇厢,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,716評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡晒喷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,794評(píng)論 3 343
  • 正文 我和宋清朗相戀三年孝偎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片凉敲。...
    茶點(diǎn)故事閱讀 40,928評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡衣盾,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出爷抓,到底是詐尸還是另有隱情雨效,我是刑警寧澤,帶...
    沈念sama閱讀 36,583評(píng)論 5 351
  • 正文 年R本政府宣布废赞,位于F島的核電站徽龟,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏唉地。R本人自食惡果不足惜据悔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,264評(píng)論 3 336
  • 文/蒙蒙 一传透、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧极颓,春花似錦朱盐、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,755評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至骇径,卻和暖如春躯肌,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背破衔。 一陣腳步聲響...
    開封第一講書人閱讀 33,869評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工清女, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人晰筛。 一個(gè)月前我還...
    沈念sama閱讀 49,378評(píng)論 3 379
  • 正文 我出身青樓嫡丙,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親读第。 傳聞我的和親對(duì)象是個(gè)殘疾皇子曙博,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,937評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • 雙十一前的一個(gè)多月,所有的電商相關(guān)的系統(tǒng)都在進(jìn)行壓測(cè)怜瞒,不斷的優(yōu)化系統(tǒng)父泳,我們的電商ERP系統(tǒng)也進(jìn)行了一個(gè)多月的壓測(cè)和...
    鶴子青云上閱讀 695評(píng)論 0 0
  • 線程狀態(tài) NEW:通過(guò)Thread類創(chuàng)建了一個(gè)線程,在調(diào)用start()方法之前的狀態(tài)盼砍。RUNNABLE:運(yùn)行狀態(tài)...
    alexwu59閱讀 1,691評(píng)論 0 2
  • 理解CPU 上下文切換 根據(jù)任務(wù)的不同,CPU 的上下文切換就可以分為幾個(gè)不同的場(chǎng)景逝她,也就是進(jìn)程上下文切換浇坐、線程上...
    wayyyy閱讀 837評(píng)論 0 0
  • 查看CPU上下文切換的命令 了解了CPU上下文切會(huì)導(dǎo)致系統(tǒng)負(fù)載升高,下面我們介紹下用linux命令查看系統(tǒng)CPU上...
    崔天浩閱讀 825評(píng)論 0 1
  • what 大多數(shù)RTOS實(shí)現(xiàn)都提供了類似此一對(duì)函數(shù)功能的對(duì)應(yīng)接口黔宛,需要開發(fā)者主動(dòng)地分別在中斷服務(wù)函數(shù)(ISR)的開...
    蘇里南公牛閱讀 1,635評(píng)論 0 0