看以下代碼java
public class Test { StringBuffer stb = new StringBuffer(); public void test1(){ //jvm的優化,鎖的粗化 stb.append("1"); stb.append("2"); stb.append("3"); stb.append("4"); }
首先咱們要清除StringBuffer是線程安全的,由於它在每個方法上都加了synchronized鎖,下圖是StringBuffer的源碼安全
按照正常的理解synchronized是對當前對象加鎖,那麼咱們調用了四次append方法,那麼jvm是將這把對象鎖加了四次嗎?以下圖:多線程
那這樣的化,jvm就須要加四次鎖,固然也要釋放四次鎖,頻繁加解鎖引發線程上下文的切換,很是消耗性能,因此jvm作了優化,只加一次鎖,叫作鎖的粗化,能夠理解爲將鎖的顆粒度放大app
如圖看下面代碼jvm
public void test2(){ //jvm的優化,JVM不會對同步塊進行加鎖 synchronized (new Object()) { //僞代碼:不少邏輯 //jvm是否會加鎖? //jvm會進行逃逸分析 } }
這個地方加鎖等於沒有加鎖,由於每一個線程都會new object,你們都不會用同一把鎖,jvm分析優化後不會對這種代碼加鎖(逃逸分析),因此,咱們平時加鎖必定要注意,加鎖要加同一把鎖。性能
synchronized的鎖的狀態總共有四種,無鎖狀態、偏向鎖、輕量級鎖和重量級鎖。隨着鎖的競爭,鎖能夠從偏向鎖升級到輕量級鎖,再升級的重量級鎖,可是鎖的升級是單向的,也就是說只能從低到高升級,鎖狀態的升級不可逆。優化
JDK1.6版本以後對synchronized的實現進行了各類優化,如自旋鎖、偏向鎖和輕量級鎖 並默認開啓偏向鎖 開啓偏向鎖:-XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0 關閉偏向鎖:-XX:-UseBiasedLocking。若是直接上來就是重量級鎖,那麼實在是太消耗資源了。spa
注意一下幾點:操作系統
線程1獲取輕量級鎖後會將Object Mark Word 複製本身的一份到本身的棧空間,而後在本身的棧空間開闢一個指針lockerecord 指向Object Mark Word,同時Object Mark Word也會指向lockerecord,當線程1執行完代碼塊釋放輕量級鎖以後,發現Object Mark Word不在指向本身,說明當前鎖已經改成重量級鎖,那麼它會喚醒阻塞隊列中全部線程從新競爭鎖。線程
總結:偏向鎖,輕量級鎖都是基於Object Mark Word的標記實現,java儘量避免使用重量級鎖。