面試官:?jiǎn)魏?CPU 支持 Java 多線程嗎?為什么?被問(wèn)懵了!
回復(fù)架構(gòu)師獲取資源
大家好,我是你們的朋友架構(gòu)君,一個(gè)會(huì)寫(xiě)代碼吟詩(shī)的架構(gòu)師。
'javajgs.com';
原文:
blog.csdn.net/alex_xfboy/article/details/90722654
時(shí)間片
多任務(wù)系統(tǒng)往往需要同時(shí)執(zhí)行多道作業(yè)。作業(yè)數(shù)往往大于機(jī)器的CPU數(shù),然而一顆CPU同時(shí)只能執(zhí)行一項(xiàng)任務(wù),如何讓用戶(hù)感覺(jué)這些任務(wù)正在同時(shí)進(jìn)行呢? 操作系統(tǒng)的設(shè)計(jì)者 巧妙地利用了時(shí)間片輪轉(zhuǎn)的方式
時(shí)間片是CPU分配給各個(gè)任務(wù)(線程)的時(shí)間!
“思考:?jiǎn)魏薈PU為何也支持多線程呢?
”
線程上下文是指某一時(shí)間點(diǎn) CPU 寄存器和程序計(jì)數(shù)器的內(nèi)容,CPU通過(guò)時(shí)間片分配算法來(lái)循環(huán)執(zhí)行任務(wù)(線程),因?yàn)闀r(shí)間片非常短,所以CPU通過(guò)不停地切換線程執(zhí)行。
換言之,單CPU這么頻繁,多核CPU一定程度上可以減少上下文切換。
超線程
現(xiàn)代CPU除了處理器核心之外還包括寄存器、L1L2緩存這些存儲(chǔ)設(shè)備、浮點(diǎn)運(yùn)算單元、整數(shù)運(yùn)算單元等一些輔助運(yùn)算設(shè)備以及內(nèi)部總線等。一個(gè)多核的CPU也就是一個(gè)CPU上有多個(gè)處理器核心,就意味著程序的不同線程需要經(jīng)常在CPU之間的外部總線上通信,同時(shí)還要處理不同CPU之間不同緩存導(dǎo)致數(shù)據(jù)不一致的問(wèn)題。
超線程這個(gè)概念是Intel提出的,簡(jiǎn)單來(lái)說(shuō)是在一個(gè)CPU上真正的并發(fā)兩個(gè)線程,由于CPU都是分時(shí)的(如果兩個(gè)線程A和B,A正在使用處理器核心,B正在使用緩存或者其他設(shè)備,那AB兩個(gè)線程就可以并發(fā)執(zhí)行,但是如果AB都在訪問(wèn)同一個(gè)設(shè)備,那就只能等前一個(gè)線程執(zhí)行完后一個(gè)線程才能執(zhí)行)。實(shí)現(xiàn)這種并發(fā)的原理是 在CPU里加了一個(gè)協(xié)調(diào)輔助核心,根據(jù)Intel提供的數(shù)據(jù),這樣一個(gè)設(shè)備會(huì)使得設(shè)備面積增大5%,但是性能提高15%~30%。
上下文切換
線程切換,同一進(jìn)程中的兩個(gè)線程之間的切換 進(jìn)程切換,兩個(gè)進(jìn)程之間的切換 模式切換,在給定線程中,用戶(hù)模式和內(nèi)核模式的切換 地址空間切換,將虛擬內(nèi)存切換到物理內(nèi)存
CPU切換前把當(dāng)前任務(wù)的狀態(tài)保存下來(lái),以便下次切換回這個(gè)任務(wù)時(shí)可以再次加載這個(gè)任務(wù)的狀態(tài),然后加載下一任務(wù)的狀態(tài)并執(zhí)行。任務(wù)的狀態(tài)保存及再加載, 這段過(guò)程就叫做上下文切換。
每個(gè)線程都有一個(gè)程序計(jì)數(shù)器(記錄要執(zhí)行的下一條指令),一組寄存器(保存當(dāng)前線程的工作變量),堆棧(記錄執(zhí)行歷史,其中每一幀保存了一個(gè)已經(jīng)調(diào)用但未返回的過(guò)程)。
寄存器 是 CPU 內(nèi)部的數(shù)量較少但是速度很快的內(nèi)存(與之對(duì)應(yīng)的是 CPU 外部相對(duì)較慢的 RAM 主內(nèi)存)。寄存器通過(guò)對(duì)常用值(通常是運(yùn)算的中間值)的快速訪問(wèn)來(lái)提高計(jì)算機(jī)程序運(yùn)行的速度。
程序計(jì)數(shù)器是一個(gè)專(zhuān)用的寄存器,用于表明指令序列中 CPU 正在執(zhí)行的位置,存的值為正在執(zhí)行的指令的位置或者下一個(gè)將要被執(zhí)行的指令的位置。
掛起當(dāng)前任務(wù)(線程/進(jìn)程),將這個(gè)任務(wù)在 CPU 中的狀態(tài)(上下文)存儲(chǔ)于內(nèi)存中的某處 恢復(fù)一個(gè)任務(wù)(線程/進(jìn)程),在內(nèi)存中檢索下一個(gè)任務(wù)的上下文并將其在 CPU 的寄存器中恢復(fù) 跳轉(zhuǎn)到程序計(jì)數(shù)器所指向的位置(即跳轉(zhuǎn)到任務(wù)被中斷時(shí)的代碼行),以恢復(fù)該進(jìn)程在程序中

線程上下文切換會(huì)有什么問(wèn)題呢?
上下文切換會(huì)導(dǎo)致額外的開(kāi)銷(xiāo),常常表現(xiàn)為高并發(fā)執(zhí)行時(shí)速度會(huì)慢串行,因此減少上下文切換次數(shù)便可以提高多線程程序的運(yùn)行效率。
直接消耗:指的是CPU寄存器需要保存和加載, 系統(tǒng)調(diào)度器的代碼需要執(zhí)行, TLB實(shí)例需要重新加載, CPU 的pipeline需要刷掉 間接消耗:指的是多核的cache之間得共享數(shù)據(jù), 間接消耗對(duì)于程序的影響要看線程工作區(qū)操作數(shù)據(jù)的大小
切換查看
Linux系統(tǒng)下可以使用vmstat命令來(lái)查看上下文切換的次數(shù), 其中cs列就是指上下文切換的數(shù)目(一般情況下, 空閑系統(tǒng)的上下文切換每秒大概在1500以下)

線程調(diào)度
搶占式調(diào)度
指的是每條線程執(zhí)行的時(shí)間、線程的切換都由系統(tǒng)控制,系統(tǒng)控制指的是在系統(tǒng)某種運(yùn)行機(jī)制下,可能每條線程都分同樣的執(zhí)行時(shí)間片,也可能是某些線程執(zhí)行的時(shí)間片較長(zhǎng),甚至某些線程得不到執(zhí)行的時(shí)間片。在這種機(jī)制下,一個(gè)線程的堵塞不會(huì)導(dǎo)致整個(gè)進(jìn)程堵塞。
java使用的線程調(diào)使用搶占式調(diào)度,Java中線程會(huì)按優(yōu)先級(jí)分配CPU時(shí)間片運(yùn)行,且優(yōu)先級(jí)越高越優(yōu)先執(zhí)行,但優(yōu)先級(jí)高并不代表能獨(dú)自占用執(zhí)行時(shí)間片,可能是優(yōu)先級(jí)高得到越多的執(zhí)行時(shí)間片,反之,優(yōu)先級(jí)低的分到的執(zhí)行時(shí)間少但不會(huì)分配不到執(zhí)行時(shí)間。

協(xié)同式調(diào)度
指某一線程執(zhí)行完后主動(dòng)通知系統(tǒng)切換到另一線程上執(zhí)行,這種模式就像接力賽一樣,一個(gè)人跑完自己的路程就把接力棒交接給下一個(gè)人,下個(gè)人繼續(xù)往下跑。線程的執(zhí)行時(shí)間由線程本身控制,線程切換可以預(yù)知,不存在多線程同步問(wèn)題,但它有一個(gè)致命弱點(diǎn):如果一個(gè)線程編寫(xiě)有問(wèn)題,運(yùn)行到一半就一直堵塞,那么可能導(dǎo)致整個(gè)系統(tǒng)崩潰。

線程讓出cpu的情況
當(dāng)前運(yùn)行線程主動(dòng)放棄CPU,JVM暫時(shí)放棄CPU操作(基于時(shí)間片輪轉(zhuǎn)調(diào)度的JVM操作系統(tǒng)不會(huì)讓線程永久放棄CPU,或者說(shuō)放棄本次時(shí)間片的執(zhí)行權(quán)),例如調(diào)用 yield()方法。當(dāng)前運(yùn)行線程因?yàn)槟承┰蜻M(jìn)入阻塞狀態(tài),例如阻塞在I/O上 當(dāng)前運(yùn)行線程結(jié)束,即運(yùn)行完 run()方法里面的任務(wù)
引起線程上下文切換的因素
當(dāng)前執(zhí)行任務(wù)(線程)的時(shí)間片用完之后,系統(tǒng)CPU正常調(diào)度下一個(gè)任務(wù) 中斷處理,在中斷處理中,其他程序”打斷”了當(dāng)前正在運(yùn)行的程序。當(dāng)CPU接收到中斷請(qǐng)求時(shí),會(huì)在正在運(yùn)行的程序和發(fā)起中斷請(qǐng)求的程序之間進(jìn)行一次上下文切換。中斷分為硬件中斷和軟件中斷,軟件中斷包括因?yàn)镮O阻塞、未搶到資源或者用戶(hù)代碼等原因,線程被掛起。 用戶(hù)態(tài)切換,對(duì)于一些操作系統(tǒng),當(dāng)進(jìn)行用戶(hù)態(tài)切換時(shí)也會(huì)進(jìn)行一次上下文切換,雖然這不是必須的。 多個(gè)任務(wù)搶占鎖資源,在多任務(wù)處理中,CPU會(huì)在不同程序之間來(lái)回切換,每個(gè)程序都有相應(yīng)的處理時(shí)間片,CPU在兩個(gè)時(shí)間片的間隔中進(jìn)行上下文切換
因此優(yōu)化手段有:
無(wú)鎖并發(fā)編程,多線程處理數(shù)據(jù)時(shí),可以用一些辦法來(lái)避免使用鎖,如將數(shù)據(jù)的ID按照Hash取模分段,不同的線程處理不同段的數(shù)據(jù) CAS算法,Java的Atomic包使用CAS算法來(lái)更新數(shù)據(jù),而不需要加鎖 使用最少線程 協(xié)程,單線程里實(shí)現(xiàn)多任務(wù)的調(diào)度,并在單線程里維持多個(gè)任務(wù)間的切換
合理設(shè)置線程數(shù)目既可以最大化利用CPU,又可以減少線程切換的開(kāi)銷(xiāo)。
高并發(fā),低耗時(shí)的情況,建議少線程。 低并發(fā),高耗時(shí)的情況:建議多線程。 高并發(fā)高耗時(shí),要分析任務(wù)類(lèi)型、增加排隊(duì)、加大線程數(shù)
這些年小編給你分享過(guò)的干貨
2.優(yōu)質(zhì)ERP系統(tǒng)帶進(jìn)銷(xiāo)存財(cái)務(wù)生產(chǎn)功能(附源碼)
3.優(yōu)質(zhì)SpringBoot帶工作流管理項(xiàng)目(附源碼)
4.最好用的OA系統(tǒng),拿來(lái)即用(附源碼)
5.SBoot+Vue外賣(mài)系統(tǒng)前后端都有(附源碼)
6.SBoot+Vue可視化大屏拖拽項(xiàng)目(附源碼)

轉(zhuǎn)發(fā)在看就是最大的支持??
