線程與進程
- 進程:操作系統分配資源的基本單位。
- 線程:CPU調度(執行)的基本單位。共享進程的資源。
一個CPU同一時間只能執行一個線程,表象是線程切換(Context Switch)。對CPU來說,寄存器存數、ALU計算、PC(程序計數器)記錄位置。
線程切換過程
線程時間結束后,當前整個狀態(PC、寄存器等)全部拿出去放到緩存或者內存中,也成為保護現場。
線程一定是越多越好嗎
不,過多線程的切換需要資源較多。
JVM級別線程
Class啟動的Thread,JVM級別線程,對應操作系統內核線程。
當然JVM沒有規定一一對應關系,但是HotSpot實現,JVM線程:內核線程=1:1。可參見:https://www.cnblogs.com/MrSaver/p/12987454.html。還是一種線程模型是,用戶級別線程,通過虛擬的PC、虛擬寄存器,管理屬於用戶空間的線程,輕量級的線程——協程,纖程。短計算場景下優於內核線程。
注:JDK1.2之前,Synchronized由OS幫忙管理,非常的重量級鎖。
鎖的本質
鎖定對象,可參見:https://www.cnblogs.com/MrSaver/p/13024132.html。鎖上面有等待隊列,以實現調度。
CAS
這樣的代碼,結果一定不是一百萬。注意,加Volatile沒有用!
CAS(Compare And Swap),最底層是native代碼,由操作系統負責實現。樂觀鎖,馬士兵稱之為自旋鎖,本質死循環,但是一定能有執行成功的時候!
問1:如何處理ABA問題?
答:加版本處理。
問2:為什么會比重量級鎖效率高?
答:偽命題,未必,即使經歷過用戶空間的優化,具體問題具體分析。
自旋是消耗CPU資源的,如果鎖的時間長,或者自旋線程多,CPU會被大量消耗。重量級鎖有等待隊列,所有拿不到所得進入等待隊列,不需要消耗CPU資源。
問3:原子性如何實現!
答:硬件指令集提供,見下代碼!
進入之后,匯編命令:CMPXCHG。
JOL(Java Object Layout)與鎖
對象的內存布局打印信息如下:
當我們給對象加Synchronized鎖后,再打印JOL信息:
MarkWord鎖內容具體如下:
偏向鎖
偏向鎖也是JDK1.6中引入的一項鎖優化。目的是在無競爭的情況下把整個同步都消除掉,包括CAS操作。這個鎖會偏向於第一個獲得它的線程,如果在接下來的執行過程中,該鎖沒有被其他線程獲取,則持有偏向鎖的線程講永遠不需要進行同步。但是一旦有另外一個線程去嘗試獲取這個鎖時,偏向模式就宣告結束,撤銷偏向后恢復到未鎖定(01)或輕量級鎖定(00)狀態。
在統計學分析下,一個鎖大多數情況下只有一個線程再用,比如Vector、StringBuffer很多方法都會有Synchronized,但是通常業務下只有一個線程在用。
鎖升級過程
總體路徑:無鎖——偏向鎖——自旋鎖——重量級鎖。
多線程競爭下,偏向鎖(放在MarkWord)撤銷先變為自旋鎖(CAS方式),重度競爭的情況下,線程較多的情況下,升級為重量級鎖。