synchronize會使用,可是對於深層次的知識,不是很清楚,故整理一篇博客。java
簡介:安全
可以保證在同一時刻,最多隻有一個線程執行該端代碼,以達到保證併發安全效果。併發
兩種用法:性能
包括方法鎖(默認鎖對象爲this當前實例對象) 鎖某個方法
同步代碼塊鎖(本身制定鎖對象) 鎖某塊代碼
指synchronized修飾靜態的方法或指定鎖爲Class對象
概念: Java類可能有不少個對象,但只有一個Class對象。優化
本質: 所謂的類鎖,不過是Class對象的鎖而已。this
對線程訪問同步方法的7種狀況:操作系統
1. 兩個線程同時訪問一個對象的同步方法線程
2. 兩個線程訪問的是兩個對象的同步方法調試
3. 兩個線程訪問的是synchronized的靜態方法: 靜態方法帶synchronizedcode
4. 同時訪問同步方法和非同步方法,非同步方法不受影響
5. 訪問同一個對象的不一樣的普通同步方法
6. 同時訪問靜態synchronized和非靜態synchronized方法
7. 方法拋異常後,會釋放鎖
小結核心:
1. 一把鎖只能同時被一個線程獲取,沒有拿到鎖的線程必須等待(1,5狀況)
2. 每一個實例都對應有本身的一把鎖,不一樣實例之間互不影響。例如: 鎖對象是.class以及synchronized修飾的是static方法的時候,全部對象共用同一把鎖(對應第2,3,4,6狀況)
3. 不管是方法正常執行完畢或者方法拋出異常,都會釋放鎖(7狀況)
synchronize性質:
原理:
調試方法:
能夠看到線層的狀態:
原理:
加鎖和釋放鎖的原理:
現象: 每個類的實例對應一把鎖,每個synchronized方法都必須得到調用該方法的實例的鎖才能夠執行,不然阻塞。
咱們指定對象就能夠了,鎖的釋放獲取由JVM去自動實現。
獲取和釋放鎖的時機: 內置鎖
每個Java對象均可以用做實現一個同步的鎖,這個鎖稱之爲內置鎖(監視器鎖)。線程在家進入代碼塊以前,會自動獲取這個鎖。退出代碼塊時候會自動釋放鎖。
得到這個內置鎖的惟一途徑,就是進入到這個鎖保護的代碼塊或者方法中。
加鎖和釋放鎖的原理: 深刻JVM
每個對象都有個對象頭,能夠存儲不少信息。
Monditorenter 和 Monditorexit指令
(聯想操做系統知識:臨界區)
每一個對象都與Monitor相關聯,而一個Monitor的lock鎖只能被一個線程同一時間得到。
一個線程嘗試得到與這個對象關聯的Monitor全部權到時候,只會發生如下三種:
1. Monitor計數器爲0,目前尚未被得到,線程獲取後計數器加1.
2. 若是Monitor已經拿到了鎖的全部權,又重入了。這樣致使計數器累加。
3. 若是Monitor已經被其餘線程持有了。我去獲取時候,只能阻塞狀態了。知道技術器變爲0,再去嘗試獲取鎖。
關於Monditorexit:
釋放對於Monitor的全部權,釋放過程就是將Monitor計數器減1.若是減完是0,當前線程再也不擁有對Monitor的全部權了,其餘的阻塞線程會再次嘗試獲取對該把鎖的全部權,不是0這是可重入進來的,能夠繼續持有這把鎖。
可重入原理: 加鎖次數計數器
JVM負責跟蹤對象被加鎖的次數。每一個對象都含有一把鎖,JVM負責跟蹤對象被加鎖的次數。
線程第一次給對象加鎖的時候,技術變爲1.每當這個相同的線程在此對象上再次得到鎖時,計數會遞增。
每當任務離開時候,技術遞減,當計數爲0到時候,鎖被徹底釋放。
synchronized缺陷:
效率低: 鎖的釋放狀況少,視圖得到鎖時候不能設置超時,不能中斷一個正在試圖得到鎖的線程。
不夠靈活(讀寫鎖更靈活): 加鎖和釋放的時機單一,每一個鎖僅有單一的條件(某個對象),可能不夠 。
沒法知道是否成功獲取到鎖
反編譯: javap -verbose xx.class
問題總結:
1. 使用注意點:
鎖對象不能爲空(鎖信息保存在頭部,對象都沒有,怎麼玩兒),做用域不宜過大(包裹的代碼塊),避免死鎖。
2. 如何選擇Lock和synchronized關鍵字
思考:
1. 多個線程等待同一個synchronized鎖的時候,JVM如何選擇下一個獲取鎖的是哪一個線程?
等待時間最長,隨機?
2. Synchronized使得同時只有一個線程能夠執行,性能較差,有什麼辦法能夠提高性能?
優化使用範圍
使用其它類型的鎖,讀寫鎖
3. 我想更靈活的控制鎖的獲取和釋放(如今釋放鎖的時機都規定死了),怎麼辦?
本身實現lock接口,可控
4. 什麼是鎖的升級,降級。什麼是JVM裏的偏向鎖,輕量級鎖,重量級鎖?
以前的版本中synchronized性能不是很好,通過後面的迭代。利用偏斜鎖,輕量級鎖,重量級鎖。JVM根據synchronized關鍵字鎖使用的次數和種種指標來對鎖進行很是有效的優化。還涉及到對象頭裏面的一些字段。
總結:
JVM會自動經過使用monitor來加鎖和解鎖,保證了同時只有一個線程能夠執行指定代碼,從而保證了線程安全,同時具備可重入和不可中斷性質。
MonitorEnter表示進入對象的監視器當中