Java線程中的用戶態(tài)和內核態(tài)解讀
Java線程中用戶態(tài)和內核態(tài)
內核態(tài)用戶態(tài)是什么?
操作系統(tǒng)對程序的執(zhí)行權限進行分級,分別為用戶態(tài)和內核態(tài)。用戶態(tài)相比內核態(tài)有較低的執(zhí)行權限,很多操作是不被操作系統(tǒng)允許的,簡單來說就是用戶態(tài)只能訪問內存,防止程序錯誤影響到其他程序,而內核態(tài)則是可以操作系統(tǒng)的程序和普通用戶程序
內核態(tài): cpu可以訪問計算機所有的軟硬件資源
用戶態(tài): cpu權限受限,只能訪問到自己內存中的數(shù)據,無法訪問其他資源
為什么要有用戶態(tài)和內核態(tài)?
系統(tǒng)需要限制不同的程序之間的訪問能力,防止程序獲取不相同程序的內存數(shù)據,或者外圍設備的數(shù)據,并發(fā)送到網絡,所有cpu劃分出兩個權限等級用戶態(tài)和內核態(tài)
用戶態(tài)和內核態(tài)的轉換

用戶應用程序在用戶態(tài)下,但是如果需要執(zhí)行一些操作例如申請內存,網絡讀寫時,自己的權限不夠,就需要轉換到內核態(tài)去讓內核去幫忙干一些事情,下面三個方式會進行轉換
1.系統(tǒng)調用
這是用戶態(tài)主動要求切換到內核態(tài)的一種方式,用戶進程通過系統(tǒng)調用申請使用操作系統(tǒng)提供的服務程序完成工作,比如前列中fork()實際上就是執(zhí)行了一個創(chuàng)建新進程的系統(tǒng)調用。而系統(tǒng)調用的機制其核心還是使用了操作系統(tǒng)為用戶特別開發(fā)的一個中斷來實現(xiàn),列表liunx的int 80h中斷
2.異常
當cpu在運行在用戶態(tài)下的程序時,發(fā)生了些某些事先不可知的異常,這時會觸發(fā)由當前運行進程切換此異常的內核相關程序中,也就轉到了內核態(tài)
3.外圍設備的中斷
當外圍設備完成用戶請求的操作后,會向CPU發(fā)出相應的中斷信息,這時CPU會暫停執(zhí)行下一條即將執(zhí)行的指令而去執(zhí)行與中斷信號對應的處理程序,如果先前執(zhí)行的指令時用戶態(tài)下的程序,那么這個轉換的過程自然也就發(fā)生了由用戶態(tài)到內核態(tài)的切換,比如硬盤讀寫操作完成,系統(tǒng)會切換到硬盤讀寫的中斷處理程序中執(zhí)行后續(xù)操作等
Java線程是用戶態(tài)還是內核態(tài)
Java線程在jdk1.2之前,是基于稱為"綠色線程"的用戶線程實現(xiàn),但從JDK1.3起,主流平臺上的"主流"商用Java虛擬機的線程模型普遍都被替換為基于操作系統(tǒng)原生原生線程模型來實現(xiàn),即采用1:1的線程模型
操作系統(tǒng)支持怎么樣的線程模型,在很大程度想回影響上面的Java虛擬機的線程是怎么映射的,這一點在不同的平臺上很難達成一致,因此《Java虛擬機規(guī)范》中才不去限定Java線程需要使用哪種線程模型來實現(xiàn)。
1.證明java線程不是純粹用戶級線程:java中有個fork join框架,這個框架是利用多處理技術進行maprudce的工作,也就證明了內核是可以感知到用戶線程的存在,因此才會將多個線程調度到多個處理器中。還有,java應用程序中的某個線程阻塞,是不會引起整個進程的阻塞,從這兩點看,java線程絕不是純粹的用戶級線程。
2.再來證明java線程不是純粹內核級線程:如果使用純粹的內核級線程,那么有關線程的所有管理工作都是內核完成的,用戶程序中沒有管理線程的代碼。顯然,java線程庫提供了大量的線程管理機制,因此java線程絕不是純粹的內核級線程。 綜上,java線程是混合型的線程模型,一般而言是通過lwp將用戶級線程映射到內核線程中
Java線程用戶態(tài)內核態(tài)切換
cpu采用時間輪片機制給每個線程分發(fā)執(zhí)行時間片來讓線程執(zhí)行,如果線程在進行上下文切換,堵塞,時間片用完,睡眠,\等情況,就會發(fā)生用戶態(tài)和內核態(tài)的切換
線程切換的調度器存放于內核中,中斷處理也在內核。,從這個角度來說,如果線程當前處于用戶態(tài),若要發(fā)生線程切換,必然是要先進入內核態(tài),發(fā)生狀態(tài)切換的。線程切換的原因還可能是其他類型的中斷,或者線程自身主動進入等待和睡眠.這些情況無一例外會進入內核。
但是線程當前就處于內核態(tài),也可能一樣中斷,或者主動進入等待或者睡眠,這也是一樣會發(fā)送的,但就是沒有了用戶態(tài)和內核態(tài)的狀態(tài)切換了
總而言之線程切換和狀態(tài)切換沒有直接的關聯(lián),,只不過線程切換一般都放到內核實現(xiàn)而已,當然也還有所謂的用戶級線程,也就是在用戶態(tài)直接切換線程的棧和寄存器而已,這也無需切換到內核態(tài)
用戶態(tài)和內核態(tài)切換性能問題
當發(fā)生用戶態(tài)到內核態(tài)的切換時,會發(fā)生如下過程:
- 設置處理器至內核態(tài)。
- 保存當前寄存器(棧指針、程序計數(shù)器、通用寄存器)。
- 將棧指針設置指向內核棧地址。
- 將程序計數(shù)器設置為一個事先約定的地址上,該地址上存放的是系統(tǒng)調用處理程序的起始地址。
- 而之后從內核態(tài)返回用戶態(tài)時,又會進行類似的工作。
用戶態(tài)和內核態(tài)之間的切換有一定的開銷,如果頻繁發(fā)生切換勢必會帶來很大的開銷,所以要想盡一切辦法來減少切換
避免頻繁切換
因為線程的切換會導致用戶態(tài)和內核態(tài)之間的切換,所以減少線程切換也會減少用戶態(tài)和內核態(tài)之間的切換。那么如何減少線程切換呢?
- 無鎖并發(fā)編程。多線程競爭鎖時,加鎖、釋放鎖會導致比較多的上下文切換
- CAS算法。使用CAS避免加鎖,避免阻塞線程
- 使用最少的線程。避免創(chuàng)建不需要的線程協(xié)程。在單線程里實現(xiàn)多任務的調度,并在單線程里維持多個任務間的切換
用戶態(tài)和內核態(tài)的區(qū)別
操作系統(tǒng)需要兩種CPU狀態(tài)
- 內核態(tài)(Kernel Mode):運行操作系統(tǒng)程序,操作硬件
- 用戶態(tài)(User Mode):運行用戶程序
指令劃分
- 特權指令:只能由操作系統(tǒng)使用、用戶程序不能使用的指令。 舉例:啟動I/O 內存清零 修改程序狀態(tài)字 設置時鐘 允許/禁止終端 停機
- 非特權指令:用戶程序可以使用的指令。 舉例:控制轉移 算數(shù)運算 取數(shù)指令 訪管指令(使用戶程序從用戶態(tài)陷入內核態(tài))
特權級別
- 特權環(huán):R0、R1、R2和R3
- R0相當于內核態(tài),R3相當于用戶態(tài);
- 不同級別能夠運行不同的指令集合;
CPU狀態(tài)之間的轉換
- 用戶態(tài)--->內核態(tài):唯一途徑是通過中斷、異常、陷入機制(訪管指令)
- 內核態(tài)--->用戶態(tài):設置程序狀態(tài)字PSW
內核態(tài)與用戶態(tài)的區(qū)別
內核態(tài)與用戶態(tài)是操作系統(tǒng)的兩種運行級別,當程序運行在3級特權級上時,就可以稱之為運行在用戶態(tài)。因為這是最低特權級,是普通的用戶進程運行的特權級,大部分用戶直接面對的程序都是運行在用戶態(tài);
當程序運行在0級特權級上時,就可以稱之為運行在內核態(tài)。
運行在用戶態(tài)下的程序不能直接訪問操作系統(tǒng)內核數(shù)據結構和程序。當我們在系統(tǒng)中執(zhí)行一個程序時,大部分時間是運行在用戶態(tài)下的,在其需要操作系統(tǒng)幫助完成某些它沒有權力和能力完成的工作時就會切換到內核態(tài)(比如操作硬件)。
這兩種狀態(tài)的主要差別是:
- 處于用戶態(tài)執(zhí)行時,進程所能訪問的內存空間和對象受到限制,其所處于占有的處理器是可被搶占的
- 處于內核態(tài)執(zhí)行時,則能訪問所有的內存空間和對象,且所占有的處理器是不允許被搶占的。
通常來說,以下三種情況會導致用戶態(tài)到內核態(tài)的切換
1、系統(tǒng)調用
這是用戶態(tài)進程主動要求切換到內核態(tài)的一種方式,用戶態(tài)進程通過系統(tǒng)調用申請使用操作系統(tǒng)提供的服務程序完成工作。比如前例中fork()實際上就是執(zhí)行了一個創(chuàng)建新進程的系統(tǒng)調用。
而系統(tǒng)調用的機制其核心還是使用了操作系統(tǒng)為用戶特別開放的一個中斷來實現(xiàn),例如Linux的int 80h中斷。
用戶程序通常調用庫函數(shù),由庫函數(shù)再調用系統(tǒng)調用,因此有的庫函數(shù)會使用戶程序進入內核態(tài)(只要庫函數(shù)中某處調用了系統(tǒng)調用),有的則不會。
2、異常
當CPU在執(zhí)行運行在用戶態(tài)下的程序時,發(fā)生了某些事先不可知的異常,這時會觸發(fā)由當前運行進程切換到處理此異常的內核相關程序中,也就轉到了內核態(tài),比如缺頁異常。
3、外圍設備的中斷
當外圍設備完成用戶請求的操作后,會向CPU發(fā)出相應的中斷信號,這時CPU會暫停執(zhí)行下一條即將要執(zhí)行的指令轉而去執(zhí)行與中斷信號對應的處理程序,
如果先前執(zhí)行的指令是用戶態(tài)下的程序,那么這個轉換的過程自然也就發(fā)生了由用戶態(tài)到內核態(tài)的切換。比如硬盤讀寫操作完成,系統(tǒng)會切換到硬盤讀寫的中斷處理程序中執(zhí)行后續(xù)操作等。
這3種方式是系統(tǒng)在運行時由用戶態(tài)轉到內核態(tài)的最主要方式,其中系統(tǒng)調用可以認為是用戶進程主動發(fā)起的,異常和外圍設備中斷則是被動的。
總結
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
Springboot 項目一啟動就獲取HttpSession的兩種方法
在SpringBoot項目中,HttpSession是有狀態(tài)的,通常只有在用戶發(fā)起 HTTP請求并建立會話后才會創(chuàng)建,因此,在項目啟動時是無法獲取到 HttpSession,下面就來介紹一下Springboot啟動就獲取HttpSession,感興趣的可以了解一下2025-10-10
java網絡編程中向指定URL發(fā)送GET POST請求示例
這篇文章主要介紹了java向指定URL發(fā)送GET POST請求示例,學習JAVA網絡編程一定會用到的,大家參考使用吧2013-11-11
SpringBoot與Postman實現(xiàn)REST模擬請求的操作
這篇文章主要介紹了SpringBoot與Postman實現(xiàn)REST模擬請求的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-06-06

