天天看點

【JDK源碼】從源碼看公平鎖和非公平鎖得差別

從源碼看公平鎖和非公平鎖得差別

一:理論解釋

公平鎖:ReentrantLock通過構造器參數設定為true就是公平鎖。

非公平鎖:synchronized 關鍵字,ReentrantLock預設就是非公平鎖。

公平鎖:多個線程按照申請鎖的順序去獲得鎖,線程會直接進入隊列去排隊,永遠都是隊列的第一位才能得到鎖。

  • 優點:所有的線程都能得到資源,不會餓死在隊列中。
  • 缺點:吞吐量會下降很多,隊列裡面除了第一個線程,其他的線程都會阻塞,cpu喚醒阻塞線程的開銷會很大。

非公平鎖:多個線程去擷取鎖的時候,會直接去嘗試擷取,擷取不到,再去進入等待隊列,如果能擷取到,就直接擷取到鎖。

  • 優點:可以減少CPU喚醒線程的開銷,整體的吞吐效率會高點,CPU也不必取喚醒所有線程,會減少喚起線程的數量。
  • 缺點:你們可能也發現了,這樣可能導緻隊列中間的線程一直擷取不到鎖或者長時間擷取不到鎖,導緻餓死。

那為什麼公平鎖得性能吞吐量大,非公平鎖得吞吐量小呢?

二:從源碼角度解釋

我們以ReentrantLock為例子解釋公平鎖和非公平鎖差異。了解差異之前要知道ReentrantLock得實作原理AQS。

ReentrantLock可以通過參數來确定是否為公平鎖。

我們看到通過參數,建立公平鎖和非公平鎖。

【JDK源碼】從源碼看公平鎖和非公平鎖得差別

對于Lock得接口得lock方法,公平鎖和非公平鎖有兩種實作。

【JDK源碼】從源碼看公平鎖和非公平鎖得差別

公平鎖在加鎖前,都會通過hasQueuedPredecessors()去判斷AQS隊列是否有線程等待,如果有不會執行後面得CAS擷取鎖,傳回false,執行後面得入隊操作。

【JDK源碼】從源碼看公平鎖和非公平鎖得差別
【JDK源碼】從源碼看公平鎖和非公平鎖得差別

在非公平鎖中,擷取鎖得時候直接通過CAS嘗試擷取鎖,擷取失敗後才執行acquire()方法,而不是和公平鎖那樣直接執行acquire()方法,而且在acquire()方法中,非公平鎖也不會判斷AQS隊列中是否有線程等待擷取鎖。

【JDK源碼】從源碼看公平鎖和非公平鎖得差別

直接就是CAS擷取鎖。

【JDK源碼】從源碼看公平鎖和非公平鎖得差別

三:為什麼非公平鎖性能高

非公平鎖通過CAS擷取鎖得性能高。非公平鎖在有鎖競争得情況下每次都要執行,LockSupport.park();

來阻塞線程。

【JDK源碼】從源碼看公平鎖和非公平鎖得差別

繼續閱讀