多線程共享內存,須要解決兩個問題:多線程
競態條件 內存可見性
可使用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...指針