您好,登錄后才能下訂單哦!
前言
Java語言中有許多原生線程安全的數據結構,比如ArrayBlockingQueue、CopyOnWriteArrayList、LinkedBlockingQueue,它們線程安全的實現方式并非通過synchronized關鍵字,而是通過java.util.concurrent.locks.ReentrantLock來實現。
鎖的底層實現
無論什么語言在操作系統層面鎖的操作都會變成系統調用(System Call),以 Linux 為例,就是 futex 函數,可以把它理解為兩個函數:futex_wait(s),對變量 s 加鎖;futex_wake(s)釋放 s 上的鎖,喚醒其他線程。
在ReentrantLock中很明顯可以看到其中同步包括兩種,分別是公平的FairSync和非公平的NonfairSync。
公平鎖的作用就是嚴格按照線程啟動的順序來執行的,不允許其他線程插隊執行的;而非公平鎖是允許插隊的。
默認情況下ReentrantLock是通過非公平鎖來進行同步的,包括synchronized關鍵字都是如此,因為這樣性能會更好。
因為從線程進入了RUNNABLE狀態,可以執行開始,到實際線程執行是要比較久的時間的。
而且,在一個鎖釋放之后,其他的線程會需要重新來獲取鎖。其中經歷了持有鎖的線程釋放鎖,其他線程從掛起恢復到RUNNABLE狀態,其他線程請求鎖,獲得鎖,線程執行,這一系列步驟。如果這個時候,存在一個線程直接請求鎖,可能就避開掛起到恢復RUNNABLE狀態的這段消耗,所以性能更優化。
????/** ?????*?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()方法,以排他的方式來獲取鎖,成功了立刻返回,否則將線程加入隊列,知道成功調用為止。歡迎大家關注我的公種浩【程序員追風】,2019年多家公司java面試題整理了1000多道400多頁pdf文檔,文章都會在里面更新,整理的資料也會放在里面。
總結
上鎖的過程本身也是有時間開銷的,如果操作資源的時間比上鎖的時間還短建議使用非公平鎖可以提高系統的吞吐率;否則就老老實實的用公平鎖。
最后
歡迎大家一起交流,喜歡文章記得點個贊喲,感謝支持!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。