認識Java底層操作系統與並發基礎

一、現代計算機硬件結構

image.png

 核心部分: CPU、內存

1.CPU內部結構

image.png

  • 控制單元: 整個 CPU 的指揮控制中心
  • 運算單元: 運算器核心,執行算術運算與邏輯運算。運算器接收控制單元的指令而執行動作
  • 存儲單元: CPU 中暫時存儲數據的地方,包括 CPU 片內緩存 Cache 和 寄存器組

1.1.CPU緩存結構

現代 CPU 為瞭提升執行效率,減少 CPU 與內存的交互(交互影響 CPU 效率),一般在 CPU上集成瞭多級緩存架構,常見的為三級緩存結構

  • L1 Cache,分為數據緩存和指令緩存,邏輯核獨占
  • L2 Cache,物理核獨占,邏輯核共享
  • L3 Cache,所有物理核共享

image.png

此機器的三級緩存架構如下圖:L1 Cache又分為兩種,指令存儲單元(存指令),和邏輯存儲單元(存邏輯)。理論上一臺機器可以有多個 CPU,由插槽決定,一個 CPU 又有多核,一個核又可以由多個邏輯處理器。

image.png

寄存器是 CPU 內部元件,讀寫速度非常快。 CPU 讀取數據隻會從寄存器中去取,每個 CPU 都有一個獨有的寄存器,其他 CPU 無法訪問。采用寄存器,可以減少 CPU 訪問內存的次數,從而提高瞭 CPU 的工作速度。

越靠近 CPU 讀取速度越快,摩爾定律中,CPU 以每18個月翻一番的速度在發展,而內存和硬盤的發展速度遠遠跟不上。為瞭解決 CPU 運算速度和 I\O 速度不匹配的問題,CPU 開始被內置瞭少量的高速緩存 Lx Cache(CPU空間有限,存儲元件大小受限)。

  • 存儲器存儲空間大小: 內存 > L3 Cache > L2 Cache > L1 Cache > 寄存器
  • 存儲器讀取速度快慢: 寄存器 > L1 Cache > L2 Cache > L3 Cache > 內存
  • 緩存是由最小的存儲區塊— 緩存行(CacheLine) 組成,緩存行大小通常為64byte。我的機器L1的緩存大小時512K,則由512 * 1024/64個緩存行組成。

CPU讀取存儲器數據過程: CPU 僅能直接從寄存器中獲取數據。 假設數據 x = 0 在內存中,則它的取值過程如下:

判斷寄存器中是否存在

不存在則遍歷L1 Cache 看是否存在,不存在遍歷L2 Cache,L2 Cache 中沒有,遍歷L3 Cache。中間過程存在,則會把 Cache 行鎖住,拷貝到上一級,直至到寄存器。

Cache 中沒有則區內存中找,先通知內存控制器占用總線帶寬,通知內存加鎖,發起內存讀請求,等待回應,回應數據拷貝到L3 Cache。 註意:整個過程加鎖直至到CPU才會解開

局部性原理:在CPU訪問存儲設備時,無論是存取數據還是存取指令,都趨於聚集在一片連續的區域中。

這種局部性原理又有兩種:

  • 時間局部性(Temporal Locality): 如果一個信息項正在被訪問,那麼在近期它很可能還會被再次訪問。 比如循環、遞歸、方法的反復調用等。
  • 空間局部性(Spatial Locality): 如果一個存儲器的位置被引用,那麼將來他附近的位置也會被引用。 比如順序執行的代碼、連續創建的兩個對象、數組等。

空間局部性的例子: 一個很大的二維數組,累加求和一行一行加會比一列一列累加快很多。在CPU 在內存中讀取數據時會將附件的數據都讀進去。

1.2.CPU運行安全等級

CPU被劃分為 4 個運行級別:

  •  ring0 內核態
  •  ring1
  •  ring2
  •  ring3 用戶態

Linux 和 Windows 都隻用到瞭兩個級別:ring0ring3,操作系統內部內部程序指令通常運行在 ring0 級別,操作系統以外的第三方程序運行在 ring3 級別,第三方程序如果要調用操作系統內部函數功能,由於運行安全級別不夠,必須切換CPU運行狀態,從 ring3 切換到 ring0, 然後執行系統函數,創建線程,線程阻塞喚醒是重型操作,因為CPU要切換運行狀態。 

JVM 創建線程是 CPU 的流程:

  • 第一步:CPU 從 ring3 切換 ring0 創建線程
  • 第二步: 創建完畢,CPU從 ring0 切回 ring3
  • 第三步: 線程執行JVM程序
  • 第四步: 線程執行完畢,銷毀切回 ring0
  • 第五步: 線程銷毀,切回 ring3

2.操作系統內存管理

為瞭使程序運行安全隔離與穩定,操作系統有用戶空間內核空間兩個概念。以 32位操作系統4G大小的內存空間為例:

image.png

Linux 為內核代碼和數據結構預留瞭幾個頁框,這些頁永遠不會被轉出到磁盤上(4GB內存空間,用戶程序可使用3GB)。如圖綠色部分的線性地址可由用戶代碼和內核代碼進行引用(即用戶空間)。黃色部分的線性地址隻能由內核代碼進行訪問(即內核空間)。

進程與線程隻能運行在用戶方式(usermode) 或 內核方式(kernelmode) 下。用戶程序運行在用戶方式下,而系統調用運行在內核方式下。

用戶方式下使用一般的堆棧(用戶空間的堆棧),內核方式下使用固定大小的堆棧(內核空間的堆棧,一般為一個內存頁的大小),即每個進程與線程其實有兩個堆棧,分別運行與用戶態內核態

CPU調度的基本單位線程,也劃分為:

  • 內核線程模型(KLT): Java使用,內核保存線程的狀態和上下文信息,線程阻塞不會引起進程阻塞。在多處理器系統上,多線程在多處理器上並行運行。線程的創建、調度和管理由內核完成,效率比ULT要慢,比進程操作快。
  • 用戶線程模型(ULT): 不依賴操作系統核心,應用提供創建、同步、調度和管理線程的函數來控制用戶線程。不需要用戶態/內核態切換,速度快。內核對ULT無感知,線程阻塞則進程(包括它的所有線程)阻塞

image.png

 線程都有兩個堆棧,一個在用戶空間,一個在內核空間。阻塞、創建、殺死線程將拋棄用戶空間的堆棧,轉移到內核空間,執行完畢後再轉移到用戶空間。

3.進程與線程

進程: 操作系統資源分配的最小單位,例如:啟動一個 Java 程序,操作系統就會創建一個Java 進程,進程中可以包含多個線程。

線程: 操作系統調度CPU的最小單元,線程都擁有各自的計數器、堆棧和局部變量等屬性, 並且能夠訪問共享的內存變量。CPU 在這些線程上高速切換,讓使用者感覺到這些線程在同時執行(並發)。

線程上下切換: 保存上一個線程運行的中間狀態,執行下一個線程

image.png

  • 串行: 時間上不可重疊,前一個任務沒完成,下一個任務隻能等待
  • 並行: 時間上是重疊的,兩個任務在同一時刻互不幹擾的同時執行
  • 並發: 運行兩個任務彼此幹擾,同一時間點,隻有一個任務執行,交替執行

到此這篇關於認識Java底層操作系統與並發基礎的文章就介紹到這瞭,更多相關Java底層操作系統內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: