偏向鎖不像自旋鎖、讀寫鎖或者synchronize修飾詞這樣的同步,它其實是JVM內置的一種鎖機制,自JDK1.6后默認啟用。換句話說,這種鎖不是咱程序員能用代碼來瞎操心的,JVM自己會去操心的。真想要瞎操心,就得改JVM的啟動參數:
啟用參數: -XX:+UseBiasedLocking
關閉延遲: -XX:BiasedLockingStartupDelay=0 禁用參數: -XX:-UseBiasedLocking
既然無需我們操心,那么了解一下也是好的。偏向鎖偏向於第一個獲得它的線程,如果在接下來的執行過程中,該鎖沒有被其他的線程獲取,那么持有偏向鎖的線程無需再進行同步。很明顯,當鎖的競爭情況很少出現時,偏向鎖就能提高性能,因為它比輕量級鎖(如自旋鎖)少了一步:CAS。
偏向鎖的加鎖和解鎖有點像可重入鎖,它都得先知道取得鎖的線程是誰,拿到鎖的身份證(線程ID),下次相同的線程來了,啥都別說了,直接走快速通道pass。但如果鎖的競爭比較激烈,那么偏向鎖並無太大用處。我們來看看,在自旋鎖和synchronize同步方法兩種情況下,偏向鎖的實際時延比較,這里用的是jdk1.8版本。
一、自旋鎖:代碼參見自旋鎖淺析的testSpinLock方法
1、默認耗時:
count值:100000, 耗時:25毫秒.
2、開啟偏向鎖,啟動默認五秒之后生效:-XX:+UseBiasedLocking
count值:100000, 耗時:32毫秒.
3、開啟偏向鎖,立即生效:-XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0
count值:100000, 耗時:102毫秒.
4、關閉偏向鎖:-XX:-UseBiasedLocking
count值:100000, 耗時:30毫秒.
我們可以看到,默認時延是最少的,因為JVM會自動優化,而無時延開啟偏向鎖是最高的,不開啟偏向鎖和開啟但需要5秒啟動(這時線程早跑完了,跟不開啟差不多)跟默認時延差不多。
二、synchronize同步方法:代碼參見讀寫鎖淺析的TestMyReadWriteLock方法,需要增加全局變量:
private long startTime = 0L;
在before方法開始處加入該變量的賦值:
startTime = System.currentTimeMillis();
再加上after方法:
@After public void after() { System.out.printf("耗時:%d毫秒.\n", System.currentTimeMillis() - startTime); }
1、默認耗時:
耗時:1076毫秒.
2、開啟偏向鎖
耗時:1090毫秒.
3、開啟偏向鎖,立即生效
耗時:1099毫秒.
4、關閉偏向鎖
耗時:1078毫秒.
以上對比發現,這偏向鎖開不開都差不多。