認(rèn)識Java底層操作系統(tǒng)與并發(fā)基礎(chǔ)
一、現(xiàn)代計算機(jī)硬件結(jié)構(gòu)
核心部分: CPU、內(nèi)存
1.CPU內(nèi)部結(jié)構(gòu)
- 控制單元: 整個 CPU 的指揮控制中心
- 運(yùn)算單元: 運(yùn)算器核心,執(zhí)行算術(shù)運(yùn)算與邏輯運(yùn)算。運(yùn)算器接收控制單元的指令而執(zhí)行動作
- 存儲單元: CPU 中暫時存儲數(shù)據(jù)的地方,包括 CPU 片內(nèi)緩存 Cache 和 寄存器組
1.1.CPU緩存結(jié)構(gòu)
現(xiàn)代 CPU 為了提升執(zhí)行效率,減少 CPU 與內(nèi)存的交互(交互影響 CPU 效率),一般在 CPU上集成了多級緩存架構(gòu),常見的為三級緩存結(jié)構(gòu)
- L1 Cache,分為數(shù)據(jù)緩存和指令緩存,邏輯核獨(dú)占
- L2 Cache,物理核獨(dú)占,邏輯核共享
- L3 Cache,所有物理核共享
此機(jī)器的三級緩存架構(gòu)如下圖:L1 Cache又分為兩種,指令存儲單元(存指令),和邏輯存儲單元(存邏輯)。理論上一臺機(jī)器可以有多個 CPU,由插槽決定,一個 CPU 又有多核,一個核又可以由多個邏輯處理器。
寄存器是 CPU 內(nèi)部元件,讀寫速度非???。 CPU 讀取數(shù)據(jù)只會從寄存器中去取,每個 CPU 都有一個獨(dú)有的寄存器,其他 CPU 無法訪問。采用寄存器,可以減少 CPU 訪問內(nèi)存的次數(shù),從而提高了 CPU 的工作速度。
越靠近 CPU 讀取速度越快,摩爾定律中,CPU 以每18個月翻一番的速度在發(fā)展,而內(nèi)存和硬盤的發(fā)展速度遠(yuǎn)遠(yuǎn)跟不上。為了解決 CPU 運(yùn)算速度和 I\O 速度不匹配的問題,CPU 開始被內(nèi)置了少量的高速緩存 Lx Cache(CPU空間有限,存儲元件大小受限)。
- 存儲器存儲空間大?。?內(nèi)存 > L3 Cache > L2 Cache > L1 Cache > 寄存器
- 存儲器讀取速度快慢: 寄存器 > L1 Cache > L2 Cache > L3 Cache > 內(nèi)存
- 緩存是由最小的存儲區(qū)塊--- 緩存行(CacheLine) 組成,緩存行大小通常為64byte。我的機(jī)器L1的緩存大小時512K,則由512 * 1024/64個緩存行組成。
CPU讀取存儲器數(shù)據(jù)過程: CPU 僅能直接從寄存器中獲取數(shù)據(jù)。 假設(shè)數(shù)據(jù) x = 0 在內(nèi)存中,則它的取值過程如下:
判斷寄存器中是否存在
不存在則遍歷L1 Cache 看是否存在,不存在遍歷L2 Cache,L2 Cache 中沒有,遍歷L3 Cache。中間過程存在,則會把 Cache 行鎖住,拷貝到上一級,直至到寄存器。
Cache 中沒有則區(qū)內(nèi)存中找,先通知內(nèi)存控制器占用總線帶寬,通知內(nèi)存加鎖,發(fā)起內(nèi)存讀請求,等待回應(yīng),回應(yīng)數(shù)據(jù)拷貝到L3 Cache。 注意:整個過程加鎖直至到CPU才會解開
局部性原理:在CPU訪問存儲設(shè)備時,無論是存取數(shù)據(jù)還是存取指令,都趨于聚集在一片連續(xù)的區(qū)域中。
這種局部性原理又有兩種:
- 時間局部性(Temporal Locality): 如果一個信息項(xiàng)正在被訪問,那么在近期它很可能還會被再次訪問。 比如循環(huán)、遞歸、方法的反復(fù)調(diào)用等。
- 空間局部性(Spatial Locality): 如果一個存儲器的位置被引用,那么將來他附近的位置也會被引用。 比如順序執(zhí)行的代碼、連續(xù)創(chuàng)建的兩個對象、數(shù)組等。
空間局部性的例子: 一個很大的二維數(shù)組,累加求和一行一行加會比一列一列累加快很多。在CPU 在內(nèi)存中讀取數(shù)據(jù)時會將附件的數(shù)據(jù)都讀進(jìn)去。
1.2.CPU運(yùn)行安全等級
CPU被劃分為 4 個運(yùn)行級別:
- ring0 內(nèi)核態(tài)
- ring1
- ring2
- ring3 用戶態(tài)
Linux 和 Windows 都只用到了兩個級別:ring0、ring3,操作系統(tǒng)內(nèi)部內(nèi)部程序指令通常運(yùn)行在 ring0 級別,操作系統(tǒng)以外的第三方程序運(yùn)行在 ring3 級別,第三方程序如果要調(diào)用操作系統(tǒng)內(nèi)部函數(shù)功能,由于運(yùn)行安全級別不夠,必須切換CPU運(yùn)行狀態(tài),從 ring3 切換到 ring0, 然后執(zhí)行系統(tǒng)函數(shù),創(chuàng)建線程,線程阻塞喚醒是重型操作,因?yàn)镃PU要切換運(yùn)行狀態(tài)。
JVM 創(chuàng)建線程是 CPU 的流程:
- 第一步:CPU 從 ring3 切換 ring0 創(chuàng)建線程
- 第二步: 創(chuàng)建完畢,CPU從 ring0 切回 ring3
- 第三步: 線程執(zhí)行JVM程序
- 第四步: 線程執(zhí)行完畢,銷毀切回 ring0
- 第五步: 線程銷毀,切回 ring3
2.操作系統(tǒng)內(nèi)存管理
為了使程序運(yùn)行安全隔離與穩(wěn)定,操作系統(tǒng)有用戶空間
與內(nèi)核空間
兩個概念。以 32位操作系統(tǒng)4G大小的內(nèi)存空間為例:
Linux 為內(nèi)核代碼和數(shù)據(jù)結(jié)構(gòu)預(yù)留了幾個頁框,這些頁永遠(yuǎn)不會被轉(zhuǎn)出到磁盤上(4GB內(nèi)存空間,用戶程序可使用3GB)。如圖綠色部分的線性地址可由用戶代碼和內(nèi)核代碼進(jìn)行引用(即用戶空間)。黃色部分的線性地址只能由內(nèi)核代碼進(jìn)行訪問(即內(nèi)核空間)。
進(jìn)程與線程只能運(yùn)行在用戶方式(usermode) 或 內(nèi)核方式(kernelmode) 下。用戶程序運(yùn)行在用戶方式下,而系統(tǒng)調(diào)用運(yùn)行在內(nèi)核方式下。
用戶方式下使用一般的堆棧(用戶空間的堆棧),內(nèi)核方式下使用固定大小的堆棧(內(nèi)核空間的堆棧,一般為一個內(nèi)存頁的大小),即每個進(jìn)程與線程其實(shí)有兩個堆棧,分別運(yùn)行與用戶態(tài)與內(nèi)核態(tài)。
CPU調(diào)度的基本單位線程,也劃分為:
- 內(nèi)核線程模型(KLT): Java使用,內(nèi)核保存線程的狀態(tài)和上下文信息,線程阻塞不會引起進(jìn)程阻塞。在多處理器系統(tǒng)上,多線程在多處理器上并行運(yùn)行。線程的創(chuàng)建、調(diào)度和管理由內(nèi)核完成,效率比ULT要慢,比進(jìn)程操作快。
- 用戶線程模型(ULT): 不依賴操作系統(tǒng)核心,應(yīng)用提供創(chuàng)建、同步、調(diào)度和管理線程的函數(shù)來控制用戶線程。不需要用戶態(tài)/內(nèi)核態(tài)切換,速度快。內(nèi)核對ULT無感知,線程阻塞則進(jìn)程(包括它的所有線程)阻塞
線程都有兩個堆棧,一個在用戶空間,一個在內(nèi)核空間。阻塞、創(chuàng)建、殺死線程將拋棄用戶空間的堆棧,轉(zhuǎn)移到內(nèi)核空間,執(zhí)行完畢后再轉(zhuǎn)移到用戶空間。
3.進(jìn)程與線程
進(jìn)程: 操作系統(tǒng)資源分配的最小單位,例如:啟動一個 Java 程序,操作系統(tǒng)就會創(chuàng)建一個Java 進(jìn)程,進(jìn)程中可以包含多個線程。
線程: 操作系統(tǒng)調(diào)度CPU的最小單元,線程都擁有各自的計數(shù)器、堆棧和局部變量等屬性, 并且能夠訪問共享的內(nèi)存變量。CPU 在這些線程上高速切換,讓使用者感覺到這些線程在同時執(zhí)行(并發(fā))。
線程上下切換: 保存上一個線程運(yùn)行的中間狀態(tài),執(zhí)行下一個線程
- 串行: 時間上不可重疊,前一個任務(wù)沒完成,下一個任務(wù)只能等待
- 并行: 時間上是重疊的,兩個任務(wù)在同一時刻互不干擾的同時執(zhí)行
- 并發(fā): 運(yùn)行兩個任務(wù)彼此干擾,同一時間點(diǎn),只有一個任務(wù)執(zhí)行,交替執(zhí)行
到此這篇關(guān)于認(rèn)識Java底層操作系統(tǒng)與并發(fā)基礎(chǔ)的文章就介紹到這了,更多相關(guān)Java底層操作系統(tǒng)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MyBatis自定義typeHandler的完整實(shí)例
這篇文章主要給大家介紹了關(guān)于MyBatis自定義typeHandler的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用MyBatis具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04JavaWeb Servlet生命周期細(xì)枝末節(jié)處深究
Servlet指在服務(wù)器端執(zhí)行的一段Java代碼,可以接收用戶的請求和返回給用戶響應(yīng)結(jié)果,下面這篇文章主要給大家介紹了關(guān)于JavaWeb.servlet生命周期的相關(guān)資料,需要的朋友可以參考下2022-10-10使用Java實(shí)現(xiàn)一個能保留計算過程的計算器
計算器是我們?nèi)粘I钪谐S玫墓ぞ咧?它能夠進(jìn)行基本的數(shù)學(xué)運(yùn)算,如加法、減法、乘法和除法,而在設(shè)計一個計算器時,我們可以通過使用Java編程語言來實(shí)現(xiàn)一個簡單的控制臺計算器,并且讓它能夠保留計算過程,文中有詳細(xì)的代碼示例,需要的朋友可以參考下2023-11-11JavaWeb項(xiàng)目中springmvc和tomcat對靜態(tài)文件的處理
這篇文章主要介紹了JavaWeb項(xiàng)目中springmvc和tomcat對靜態(tài)文件的處理 的相關(guān)資料,需要的朋友可以參考下2016-07-07Java?map和bean互轉(zhuǎn)常用的方法總結(jié)
這篇文章主要給大家介紹了關(guān)于Java中map和bean互轉(zhuǎn)常用方法的相關(guān)資料,平時日常Java開發(fā),經(jīng)常會涉及到Java?Bean和Map之間的類型轉(zhuǎn)換,需要的朋友可以參考下2023-09-09