您好,登錄后才能下訂單哦!
前言
鎖作為并發共享數據,保證一致性的工具,在JAVA平臺有多種實現(如 synchronized 和 ReentrantLock等等 ) 。這些已經寫好提供的鎖為我們開發提供了便利。
在之前的文章《一文徹底搞懂面試中常問的各種“鎖” 》中介紹了Java中的各種“鎖”,可能對于不是很了解這些概念的同學來說會覺得有點繞,所以我決定拆分出來,逐步詳細的介紹一下這些鎖的來龍去脈,那么這篇文章就先來會一會“自旋鎖”。
正文
出現原因
在我們的程序中,如果存在著大量的互斥同步代碼,當出現高并發的時候,系統內核態就需要不斷的去掛起線程和恢復線程,頻繁的此類操作會對我們系統的并發性能有一定影響。同時聰明的JVM開發團隊也發現,在程序的執行過程中鎖定“共享資源“的時間片是極短的,如果僅僅是為了這點時間而去不斷掛起、恢復線程的話,消耗的時間可能會更長,那就“撿了芝麻丟了西瓜”了。
而在一個多核的機器中,多個線程是可以并行執行的。如果當后面請求鎖的線程沒拿到鎖的時候,不掛起線程,而是繼續占用處理器的執行時間,讓當前線程執行一個忙循環(自旋操作),也就是不斷在盯著持有鎖的線程是否已經釋放鎖,那么這就是傳說中的自旋鎖了。
自旋鎖開啟
雖然在JDK1.4.2的時候就引入了自旋鎖,但是需要使用“-XX:+UseSpinning”參數來開啟。在到了JDK1.6以后,就已經是默認開啟了。下面我們自己來實現一個基于CAS的簡易版自旋鎖。
public class SimpleSpinningLock { /** * 持有鎖的線程,null表示鎖未被線程持有 */ private AtomicReference<Thread> ref = new AtomicReference<>(); public void lock(){ Thread currentThread = Thread.currentThread(); while(!ref.compareAndSet(null, currentThread)){ //當ref為null的時候compareAndSet返回true,反之為false //通過循環不斷的自旋判斷鎖是否被其他線程持有 } } public void unLock() { Thread cur = Thread.currentThread(); if(ref.get() != cur){ //exception ... } ref.set(null); } }
簡簡單單幾行代碼就實現了一個簡陋的自旋鎖,下面我們來測試一下
public class TestLock { static int count = 0; public static void main(String[] args) throws InterruptedException { ExecutorService executorService = Executors.newFixedThreadPool(100); CountDownLatch countDownLatch = new CountDownLatch(100); SimpleSpinningLock simpleSpinningLock = new SimpleSpinningLock(); for (int i = 0 ; i < 100 ; i++){ executorService.execute(new Runnable() { @Override public void run() { simpleSpinningLock.lock(); ++count; simpleSpinningLock.unLock(); countDownLatch.countDown(); } }); } countDownLatch.await(); System.out.println(count); } } // 多次執行輸出均為:100 ,實現了鎖的基本功能
通過上面的代碼可以看出,自旋就是在循環判斷條件是否滿足,那么會有什么問題嗎?如果鎖被占用很長時間的話,自旋的線程等待的時間也會變長,白白浪費掉處理器資源。因此在JDK中,自旋操作默認10次,我們可以通過參數“-XX:PreBlockSpin”來設置,當超過來此參數的值,則會使用傳統的線程掛起方式來等待鎖釋放。
自適應自旋鎖
隨著JDK的更新,在1.6的時候,又出現了一個叫做“自適應自旋鎖”的玩意。它的出現使得自旋操作變得聰明起來,不再跟之前一樣死板。所謂的“自適應”意味著對于同一個鎖對象,線程的自旋時間是根據上一個持有該鎖的線程的自旋時間以及狀態來確定的。例如對于A鎖對象來說,如果一個線程剛剛通過自旋獲得到了鎖,并且該線程也在運行中,那么JVM會認為此次自旋操作也是有很大的機會可以拿到鎖,因此它會讓自旋的時間相對延長。但是如果對于B鎖對象自旋操作很少成功的話,JVM甚至可能直接忽略自旋操作。因此,自適應自旋鎖是一個更加智能,對我們的業務性能更加友好的一個鎖。
結語
本來想著在一篇文章里面把“自旋鎖”,“鎖消除”,“鎖粗化”等一些鎖優化的概念都介紹完成的,但是發現可能篇幅會比較大,對于沒怎么接觸過這一塊的同學來說理解起來會比較吃力,所以決定分開多個章節介紹,希望大家都不懂的地方可以多看幾遍,慢慢體會,相信你會有所收獲的。
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。