這是從操做系統層面來描述的java
這是從Java API層面來描述的
根據Thread.State枚舉,分爲六種狀態編程
Java的體現
兩個線程對初始值爲0的靜態變量一個作自增,一個作自減,各作5000次,結果是0嗎?
問題分析
y以上的結果多是正數、負數、零。爲何呢?由於Java中對靜態變量的自增,自減並非原子操做,要完全理解,必須從字節碼來進行分析
例如對於 i++而言(i爲靜態變量),實際會產生以下的JVM字節碼指令 :
getstatic i // 獲取靜態變量i的值
iconst_1 // 準備常量1
iadd // 自增
putstatic i // 將修改後的值存入靜態變量i
而對應 i-- 也是相似
getstatic i // 獲取靜態變量i的值
iconst_1 // 準備常量1
isub // 自減
putstatic i // 將修改後的值存入靜態變量i
而Java的內存模型以下,完成靜態變量的自增,自減須要在主存和工做內存中進行數據交換 :
若是是單線程以上8行代碼是順序執行(不會交錯)沒有問題 :
但多線程下這8行代碼可能交錯運行 :
出現負數的狀況 :
出現正數的狀況
臨界區Critical Section數組
用圖來解釋
思考
synchronized實際是用對象鎖保證了臨界區內代碼的原子性,臨界區內的代碼對外是不可分割的,不會被線程切換所打斷。
爲了加深理解,請思考下面的問題安全
成員變量和靜態變量是否線程安全?多線程
Java對象頭
以32位虛擬機爲例
普通對象
數組對象
其中Mark Word結構爲
Monitor
Monitor被翻譯爲監視器或管程
每一個Java對象均可以關聯一個Monitor對象,若是使用synchronized給對象上鎖(重量級)以後,該對象頭的Mark Word中就被設置指向Monitor對象的指針
Monitor結構以下併發
輕量級鎖的使用場景 :若是一個對象雖然有多線程訪問,但多線程訪問的時間是錯開的(也就是沒有競爭),那麼可使用輕量級鎖來優化
輕量級鎖來優化。
輕量級鎖對使用者是透明的,即語法任然是synchronized
假設有兩個方法同步塊,利用同一個對象加鎖dom
若是在嘗試加輕量級鎖的過程當中,CAS操做沒法成功,這時一種狀況就是有其餘線程爲此對象加上了輕量級鎖(有競爭),這時須要進行鎖膨脹,將輕量級鎖變爲重量級鎖。優化