Synchronized原理

多線程共享內存,須要解決兩個問題:多線程

競態條件
 內存可見性

可使用Synchronized 解決上面的問題
從幾個方面來理解synchronized測試

可重入性
內存可見性
死鎖
      可重入性是synchronized 一個特色,原理以下:
      可重入鎖是記錄鎖的持有線程,和持有數量來實現的,當被synchronized 保護的代碼時 ,檢查對象是否已經被鎖,若是是,那麼檢查是否被當前的線程鎖定。若是是,增長持有數量,若是不是被當前線程鎖定,才加入等待隊列,當釋放鎖時,減小持有數量,當數量變爲0時才釋放這個鎖。

      內存可見性
      synchronized 處理保證原子操做外,還能夠保證內存可見性。在釋放鎖的時候,內存會寫回內存,得到鎖,都會從內存中讀取最新的數據。相對volatile 來講,                  synchronized保持可見性的成本比較高。
   提個問題,volitale 內存可見性是怎麼實現的?什麼是指令重排?
死鎖
舉個例子,A,B兩個線程,A持有鎖a,等待線程B,B持有鎖b,等待線程B,這樣就陷入了相互等待?
提個問題, 死鎖的條件是啥? 如何避免死鎖?

簡單的來說,執行Synchronized方法過程大體以下:
嘗試得到鎖,若是能獲得鎖,那麼繼續,若是不能獲得鎖,那麼進入等待隊列.net

執行synchronized 修飾方法實體
 釋放鎖,等待隊列中有等待的線程,取出一個而且喚醒
  synchronized能夠來幹什麼?
           修飾代碼塊
           修飾一個方法
           修飾一個靜態的方法
           修飾一個類
 synchronized不須要主動釋放鎖 
  JVM 基於進入和退出Monitor對象來實現方法同步和代碼塊同步,monitorenter指令是在同步代碼塊開始位置,monitorexit是插入到方法結束處和異常處


Synchronized的實現原理
Synchronized是JVM實現的一種鎖,其中鎖的獲取和釋放分別是monitorenter和monitorexit指令。
該鎖在實現上分爲了偏向鎖、輕量級鎖和重量級鎖,其中偏向鎖在1.6是默認開啓的,輕量級鎖在多線程競爭的狀況下會膨脹成重量級鎖
偏向鎖
  當一線程訪問同步塊的時候,會在對象頭和棧幀中的鎖記錄存儲偏向鎖的線程ID,之後該線程進入或者退出同步塊時,不須要進行CAS操做來加鎖或者解鎖,只須要簡單測試一下對象頭的Mark Word裏是否存儲着指向當前線程的偏向鎖。若是測試成功,表示該線程得到了鎖。若是測試失敗,須要再測試一下Mark Word中偏向鎖的標識是否設置爲1(表示當前是偏向鎖) ,若是沒有設置,則使用CAS競爭鎖,若是設置了,則嘗試使用CAS將對象頭的偏向鎖指向當前線程。

輕量級鎖線程

加鎖
線程在執行同步塊以前,JVM會先在當前線程的棧幀中建立用於存儲鎖的記錄空間,並將對象頭中的MarkWord字段複製到鎖記錄中,固然會線程嘗試使用CAS將對象頭中的Mark Word替換成指向鎖記錄的指針。若是得到成功,當前線程得到了鎖,若是失敗,表示其餘線程競爭鎖,當前線程採用CAS來獲取鎖。
解鎖
 輕量級鎖解鎖的時候,會使用原子的CAS操做將 鎖記錄中的Mark Word 替換會對象頭,若是成功,表示沒有競爭發送,若是失敗,當前存在鎖競爭,鎖就會膨脹成重量級鎖。一旦鎖變成了重量級鎖,就不會再恢復到輕量級鎖,當鎖處於這個狀態下,其餘線程試圖獲取鎖是,都會被阻塞,當持有的線程釋放鎖以後會喚醒這些線程,被喚醒的線程開始新一輪的鎖爭搶。

版權聲明:本文爲CSDN博主「wangxiaoming」的原創文章,遵循CC 4.0 by-sa版權協議,轉載請附上原文出處連接及本聲明。
原文連接:https://blog.csdn.net/wangmin...指針

相關文章
相關標籤/搜索