偏向鎖是JDK1.6提出來的一種鎖優化的機制。其核心的思想是,若是程序沒有競爭,則取消以前已經取得鎖的線程同步操做。也就是說,若某一鎖被線程獲取後,便進入偏向模式,當線程再次請求這個鎖時,就無需再進行相關的同步操做了,從而節約了操做時間,若是在此之間有其餘的線程進行了鎖請求,則鎖退出偏向模式。在JVM中使用-XX:+UseBiasedLockingjava
package jvmProject; import java.util.List; import java.util.Vector; public class Biased { public static List<Integer> numberList = new Vector<Integer>(); public static void main(String[] args) { long begin = System.currentTimeMillis(); int count = 0; int startnum = 0; while(count<10000000){ numberList.add(startnum); startnum+=2; count++; } long end = System.currentTimeMillis(); System.out.println(end-begin); } }
初始化一個Vector,往裏面添加10000000個Integer對象,而後輸出時間差。以此來測試偏向鎖的性能。至於爲何要使用Vector而不使用ArrayList呢?安全
由於ArrayList是線程不安全的,Vector是線程安全的。這樣說可能還不夠具體,能夠翻看一下源碼吧。併發
Vector中的幾乎全部操做是帶有sychronized的,而ArrayList是沒有的,因此Vector是線程安全的。jvm
接下來咱們來測試一下,開啓偏向鎖和不開啓偏向鎖對程序性能的影響有多大。性能
配置JVM啓動(開啓偏向鎖)參數爲:測試
配置JVM啓動(關閉偏向鎖)參數爲:優化
Perfect!開啓偏向鎖的程序運行時間明顯較短,開啓偏向鎖比不開啓偏向鎖,在單個線程中操做一個對象的同步方法,是有必定的優點的。其實也能夠這樣理解,當只有一個線程操做帶有同步方法的Vector對象的時候,此時對Vector的操做就轉變成了對ArrayList的操做。spa
偏向鎖在鎖競爭激烈的場合沒有太強的優化效果,由於大量的競爭會致使持有鎖的線程不停地切換,鎖也很難保持在偏向模式,此時,使用偏向鎖不只得不到性能的優化,反而有可能下降系統的性能,所以,在激烈競爭的場合,能夠嘗試使用操作系統
-XX:-UseBiastedLocking參數禁用偏向鎖。線程
若是偏向鎖失敗,Java虛擬機就會讓線程申請輕量級鎖,輕量級鎖在虛擬機內部,使用一個成爲BasicObjectLock的對象實現的,這個對象內部由一個BasicLock對象和一個持有該鎖的Java對象指針組成。BasicObjectLock對象放置在Java棧幀中。在BasicLock對象內部還維護着displaced_header字段,用於備份對象頭部的Mark Word.
當一個線程持有一個對象的鎖的時候,對象頭部Mark Word信息以下
[ptr |00] locked
末尾的兩位比特爲00,整個Mark Word爲指向BasicLock對象的指針。因爲BasicObjectLock對象在線程棧中,所以該指針必然指向持有該鎖的線程棧空間。當須要判斷一個線程是否持有該對象時,只須要簡單地判斷對象頭的指針是否在當前線程的棧地址範圍便可。同時,BasicLock對象的displaced_header,備份了原對象的Mark word內容,BasicObjectLock對象的obj字段則指向持有鎖的對象頭部。
當輕量級鎖失敗,虛擬機就會使用重量級鎖。在使用重量級鎖的時,對象的Mark Word以下:
[ptr |10] monitor
重量級鎖在操做過程當中,線程可能會被操做系統層面掛起,若是是這樣,線程間的切換和調用成本就會大大提升。
自旋鎖可使線程在沒有取得鎖的時候,不被掛起,而轉去執行一個空循環,(即所謂的自旋,就是本身執行空循環),若在若干個空循環後,線程若是能夠得到鎖,則繼續執行。若線程依然不能得到鎖,纔會被掛起。
使用自旋鎖後,線程被掛起的概率相對減小,線程執行的連貫性相對增強。所以,對於那些鎖競爭不是很激烈,鎖佔用時間很短的併發線程,具備必定的積極意義,但對於鎖競爭激烈,單線程鎖佔用很長時間的併發程序,自旋鎖在自旋等待後,每每毅然沒法得到對應的鎖,不只僅白白浪費了CPU時間,最終仍是免不了被掛起的操做 ,反而浪費了系統的資源。
在JDK1.6中,Java虛擬機提供-XX:+UseSpinning參數來開啓自旋鎖,使用-XX:PreBlockSpin參數來設置自旋鎖等待的次數。
在JDK1.7開始,自旋鎖的參數被取消,虛擬機再也不支持由用戶配置自旋鎖,自旋鎖老是會執行,自旋鎖次數也由虛擬機自動調整。