Java:鎖的四中狀態:無鎖,偏向鎖,輕量級鎖,重量級鎖

Java併發編程,本身在實際項目確實不多用到,常常學了就忘,忘了在學的噁心循環。經過再次的學習,掌握一些併發編程原理和理清常常混淆的知識點。編程

synchronized

synchronized,所謂的重量級鎖。Java中每個對象均可以做爲一個鎖,表現爲:數組

  • 對於普通方法的同步,鎖是當前實例對象。
  • 對於靜態方法的同步,鎖是當前類的Class對象。
  • 對於同步方法塊,鎖是Synchronized括號裏配置的對象。

jVM基於進入和退出Monitor對象來實現方法同步和代碼同步。方法同步是使用monitorenter和monitorexit指令實現的,monitorenter指令是在編譯後插入到同步代碼塊開始的位置,monitorexit是插在方法結束處和異常處。方法同步使用另外一種實現方式,在JVM規範裏沒有詳細的說明。多線程

volatile

volatile是輕量級的synchronized,它在多處理器開發中保證了共享變量的可見性。對一個volatile變量的讀,老是能看到任意線程對這個volatile變量最後的寫入,對單個volatile變量的讀寫具備原子性。就是說,線程對volatile變量本地內存的寫入會被更新到主內存,其餘線程對同個volatile的讀取,會先將本地的設爲無效,必須從主內存中讀取。併發

鎖的狀態

鎖是存在哪裏的呢?

鎖存在Java的對象頭中的Mark Work。Mark Work默認不只存放着鎖標誌位,還存放對象hashCode等信息。運行時,會根據鎖的狀態,修改Mark Work的存儲內容。若是對象是數組類型,則虛擬機用3個字寬存儲對象頭,若是對象是非數組類型,則用2字寬存儲對象頭。在32位虛擬機中,一字寬等於四字節,即32bit。關於對象頭等相關知識,能夠參考Java虛擬機相關文章。性能

32位JVM默認狀態下Mark Work的存儲結構。 學習

32位JVM運行狀態下,Mark Work的存儲結構。
運行狀況下32位JVM的Mark Work

鎖的狀態

鎖有四種狀態:無鎖狀態、偏向鎖、輕量級鎖、重量級鎖優化

隨着鎖的競爭,鎖的狀態會從偏向鎖到輕量級鎖,再到重量級鎖。並且鎖的狀態只有升級,沒有降級。也就是隻有偏向鎖->輕量級鎖->重量級鎖,沒有重量級鎖->輕量級鎖->偏向鎖。線程

鎖名稱 描述 應用場景
偏向鎖 線程在大多數狀況下並不存在競爭條件,使用同步會消耗性能,而偏向鎖是對鎖的優化,能夠消除同步,提高性能。當一個線程得到鎖,會將對象頭的鎖標誌位設爲01,進入偏向模式.偏向鎖能夠在讓一個線程一直持有鎖,在其餘線程須要競爭鎖的時候,再釋放鎖。 只有一個線程進入臨界區
輕量級鎖 當線程A得到偏向鎖後,線程B進入競爭狀態,須要得到線程A持有的鎖,那麼線程A撤銷偏向鎖,進入無鎖狀態。線程A和線程B交替進入臨界區,偏向鎖沒法知足,膨脹到輕量級鎖,鎖標誌位設爲00。 多個線程交替進入臨界區
重量級鎖 當多線程交替進入臨界區,輕量級鎖hold得住。但若是多個線程同時進入臨界區,hold不住了,膨脹到重量級鎖 多個線程同時進入臨界區

鎖的優缺點

優勢 缺點 適用場景
偏向鎖 加鎖和解鎖不須要額外的消耗,和執行非同步方法比僅存在納秒級的差距 若是線程間存在鎖競爭,會帶來額外的鎖撤銷的消耗。 適用於只有一個線程訪問同步塊場景。
輕量級鎖 競爭的線程不會阻塞,提升了程序的響應速度。 若是始終得不到鎖競爭的線程使用自旋會消耗CPU。 追求響應時間。同步塊執行速度很是快。
重量級鎖 線程競爭不使用自旋,不會消耗CPU 線程阻塞,響應時間緩慢 追求吞吐量。同步塊執行速度較長。

總結

在鎖的狀態中,主要是理解什麼是偏向鎖,輕量級鎖,重量級,以及他們的應用場景。 3d

點個贊,老鐵

若是以爲文章有用,給文章點個贊,鐵子

本文是我的學習總結和知識備忘,如知識有誤或片面,請多加指正,謝謝orm

知識來源《Java併發編程的藝術》

相關文章
相關標籤/搜索