Synchronize深刻

  • 前言: 

  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性質:

  •  可重入       方法能夠重入,父子類能夠重入
  • 不可中斷     一旦這個鎖已經被被人得到了,如何我還想得到,我只能選擇等待或者阻塞,知作別的線程釋放這個鎖。而Lock類,擁有中斷能力。第一點,若是我以爲我等待時間長了。有權中斷如今已經獲取到鎖的線程的執行。第二點,若是我以爲我不想等待了,能夠退出。

原理:

  • 加鎖原理
  • 可重入原理
  • 可見性原理

 

 

調試方法:

 

 

 

能夠看到線層的狀態:

 

原理:

加鎖和釋放鎖的原理:

  現象: 每個類的實例對應一把鎖,每個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表示進入對象的監視器當中 

相關文章
相關標籤/搜索