JVM執行緒屬于用戶態還是內核態
當行程運行在ring3級別時為用戶態,ring0級別時為內核態
有些操作需要有內核權限才能進行,那么有三種由用戶態切換到內核態的情況:
- 系統呼叫:作業系統封裝內核指令,統一管理硬體資源,然后向用戶程式提供系統服務,用戶程式進行系統呼叫,作業系統進行檢查確保安全然后再進行相應的資源訪問操作,比如malloc(),print()呼叫write()系統輸出字串
- 例外事件:當cpu正在運行用戶態程式,發生不可預知的例外事件,就會轉用戶態,比如缺頁中斷,
- 外圍設備的中斷:當外圍設備完成請求就會向CPU發出中斷信號,此時cpu暫停下一條要執行的指令,去執行中斷信號所對應的程式
相同點和不同點:都是中斷,但是系統呼叫是主動,其他都是被動
用戶態和內核態執行緒的映射關系
一對一(內核執行緒實作)
程式使用輕量級行程和內核執行緒產生映射
缺點:輕量級行程的數量有限制,執行效率低
多對一(用戶執行緒實作)
優點:用戶執行緒數量幾乎無限制,執行效率高
缺點:一個用戶執行緒阻塞,其他執行緒也會阻塞
多對多
UT 用戶態執行緒 LWP 輕量級執行緒 KLT 內核態執行緒

優點:
- 一個用戶執行緒的阻塞不會導致所有執行緒的阻塞,因為此時還有別的內核執行緒被調度來執行,
- 多對多模型對用戶執行緒的數量沒有限制,
- 在多處理器的作業系統中,多對多模型的執行緒也能得到一定的性能提升,但提升的幅度不如一對一模型的高,在現在流行的作業系統中,大都采用多對多的模型,
用戶態執行緒:切換代價小,高并發但是容易阻塞
內核態執行緒:處理能力高,切換代價大
Java執行緒的實作
虛擬機規范中并沒有限定java執行緒需要使用哪種執行緒模型,要根據不同的平臺來說,但是無論使用哪種執行緒模型,java程式的編碼和運行都是沒有差異的
Java執行緒調度
執行緒調度有兩種:協同調度和搶占調度
協同:自己分配時間,自己切換
搶占:系統分配時間,系統決定執行緒的切換
java執行緒采用搶占調度
java執行緒的6種狀態
新建———-運行———無限期等待——–限期等待———阻塞——結束
作業系統執行緒的幾種狀態
新建———就緒————等待————運行———–結束
java和作業系統的執行緒對應關系
1.2之前(綠色執行緒 1:N),程式員為jvm開發了一個執行緒調度內核,映射到作業系統層面就是用戶態執行緒;
1.2(1:1)之后,jvmU型安澤了作業系統原生執行緒模型,映射到作業系統層面就是內核態執行緒,通過系統呼叫,將程式的執行緒交給了作業系統內核進行調度,
通過創建程序來理解

Java的Thread物件:僅僅是一個Java物件
JVM的JavaThread物件:連接著java的Thread物件與OS物件
JVM的OSThread物件:一個工具類,對OS執行緒API進行了功能性封裝
流程圖:

JVM_StartThread核心做了兩件事情:
1.創建JavaThread物件
? (1) 設定jvm執行run方法的跳板
? (2) 呼叫os::create_thread創建OSThread物件及作業系統執行緒完成三者的關聯
? os::create_thread做了一下這些:
? 創建OSThread物件,將JavaThread物件與OSThread物件進行關聯
執行緒庫
為開發人員提供創建和管理執行緒的一套API
三個主要的執行緒庫:
1)POSIX Pthreads:可以作為用戶或內核庫提供,作為 POSIX 標準的擴展
2)Win32 執行緒:用于 Window 作業系統的內核級執行緒庫
3)Java 執行緒:Java 執行緒 API 通常采用宿主系統的執行緒庫來實作,也就是說在 Win 系統上,Java 執行緒 API 通常采用 Win API 來實作,在 UNIX 類系統上,采用 Pthread 來實作,
作業系統對于鎖的實作
在硬體層面,CPU提供了原子操作、關中斷(可解決單核情況下兩個執行緒同時獲得鎖)、鎖記憶體總線的機制(解決多核情況下兩個執行緒同時獲得鎖);OS基于這幾個CPU硬體機制,就能夠實作鎖;再基于鎖,就能夠實作各種各樣的同步機制(信號量、訊息、Barrier等等等等)
synchronized的底層實作
是通過物件內部的一個監視器鎖(monitor)實作的,監視器鎖有時通過作業系統的互斥鎖來實作的,而且現在主流的java虛擬機實作中,java的執行緒是映射到作業系統原生的內核執行緒中的,那么執行緒的阻塞或喚醒,就涉及到用戶態和內核態的轉換中,所以是重量級鎖,
是一種塊結構的同步語法,經過javac反編譯之后,會在同步塊的前后分別生成monitorenter和monitorexit兩個位元組碼指令,這兩個指令都需要一個reference型別的引數來指明加鎖解鎖的物件,如果synchronized明確了物件引數,就以這個物件的參考作為reference,如果沒有指定,那就根據修飾的方法型別,來決定是區代碼所在的物件實體還是相應的class物件,
反射的性能優化
兩個地方導致性能差:getMethod和invoke,反射是一個解釋操作,臨時告訴jvm應該做什么
優化思路1:快取Method,不重復呼叫getMethod
優化思路2:借助ASM框架,使用reflectAsm,讓invoke變成直接呼叫
借反射的getDeclaredMethods獲取目標類的所有方法,然后動態生成一個繼承于MethodAccess 的子類SimpleBeanMethodAccess,動態生成一個Class檔案并load到JVM中,
SimpleBeanMethodAccess中所有方法名建立index索引,index跟方法名是映射的,根據方法名獲得index,SimpleBeanMethodAccess內部建立的switch直接分發執行相應的代碼,這樣methodAccess.invoke的時候,實際上是直接呼叫,
hashmap在jdk1.7的死回圈
多執行緒頭插法造成的,執行緒2已經完成擴容散列,鏈表變成了倒序,執行緒1再進行擴容,將倒序鏈表變成了一個正序鏈表,從而形成環形鏈表,在使用get方法時造成死回圈,
常用集合
ArrayList
首先有三種構造方法(有參,無參,指定集合引陣列成的串列)
主要就是三個方法:
1.ensureCapacityInternal得到最小擴容量,并進行擴容
2.ensureExplicitCapacity//判斷是否需要擴容,如果最小擴容量大于陣列現在的長度就呼叫grow方法
3.grow 進行位運算,擴容1.5倍,并進行判斷是否超出陣列的最大容量,
始化資料量為0,add時變為10,當 要 add 進第 1 個元素時,minCapacity 為 1,在 ensureCapacityInternal的Math.max()方法比較后,minCapacity 為 10 ,
最好在 add 大量元素之前用 ensureCapacity 方法(因為是public修飾),以減少增量重新分配的次數
Set Map
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/499517.html
標籤:Java
下一篇:RPC學習
