本人免費整理了Java高級資料,涵蓋了Java、Redis、MongoDB、MySQL、Zookeeper、Spring Cloud、Dubbo高併發分佈式等教程,一共30G,須要本身領取。
傳送門:https://mp.weixin.qq.com/s/JzddfH-7yNudmkjT0IRL8Q併發
和朋友聊天他提到:ReentrantLock 的構造函數能夠傳遞一個 bool 數據,true 時構造的是「公平鎖」、false 時構造的是「非公平鎖」。個人印象中鎖是不區分類型的,因此認爲這應該是 Java 發明的概念,因而就惡補了一下。分佈式
鎖的底層實現
不管什麼語言在操做系統層面鎖的操做都會變成系統調用(System Call),以 Linux 爲例,就是 futex 函數,能夠把它理解爲兩個函數: futex_wait(s),對變量 s 加鎖;futex_wake(s)釋放 s 上的鎖,喚醒其餘線程。函數
在ReentrantLock中很明顯能夠看到其中同步包括兩種,分別是公平的FairSync和非公平的NonfairSync。高併發
公平鎖的做用就是嚴格按照線程啓動的順序來執行的,不容許其餘線程插隊執行的;而非公平鎖是容許插隊的。性能
默認狀況下ReentrantLock是經過非公平鎖來進行同步的,包括synchronized關鍵字都是如此,由於這樣性能會更好。優化
由於從線程進入了RUNNABLE狀態,能夠執行開始,到實際線程執行是要比較久的時間的。ui
並且,在一個鎖釋放以後,其餘的線程會須要從新來獲取鎖。其中經歷了持有鎖的線程釋放鎖,其餘線程從掛起恢復到RUNNABLE狀態,其餘線程請求鎖,得到鎖,線程執行,這一系列步驟。若是這個時候,存在一個線程直接請求鎖,可能就避開掛起到恢復RUNNABLE狀態的這段消耗,因此性能更優化。spa
/** * Creates an instance of {@code ReentrantLock}. * This is equivalent to using {@code ReentrantLock(false)}. */ public ReentrantLock() { sync = new NonfairSync(); }
默認狀態,使用的ReentrantLock()就是非公平鎖。再參考以下代碼,咱們知道ReentrantLock的獲取鎖的操做是經過裝飾模式代理給sync的。操作系統
/** * Acquires the lock. * * <p>Acquires the lock if it is not held by another thread and returns * immediately, setting the lock hold count to one. * * <p>If the current thread already holds the lock then the hold * count is incremented by one and the method returns immediately. * * <p>If the lock is held by another thread then the * current thread becomes disabled for thread scheduling * purposes and lies dormant until the lock has been acquired, * at which time the lock hold count is set to one. */ public void lock() { sync.lock(); }
下面參考一下FairSync和NonfairSync對lock方法的實現:線程
/** * Sync object for non-fair locks */ static final class NonfairSync extends Sync { /** * Performs lock. Try immediate barge, backing up to normal * acquire on failure. */ final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } } /** * Sync object for fair locks */ static final class FairSync extends Sync { final void lock() { acquire(1); } }
當使用非公平鎖的時候,會馬上嘗試配置狀態,成功了就會插隊執行,失敗了就會和公平鎖的機制同樣,調用acquire()方法,以排他的方式來獲取鎖,成功了馬上返回,不然將線程加入隊列,知道成功調用爲止。