Java concurrency之非公平鎖_動力節(jié)點(diǎn)Java學(xué)院整理
獲取非公平鎖(基于JDK1.7.0_40)
非公平鎖和公平鎖在獲取鎖的方法上,流程是一樣的;它們的區(qū)別主要表現(xiàn)在“嘗試獲取鎖的機(jī)制不同”。簡單點(diǎn)說,“公平鎖”在每次嘗試獲取鎖時(shí),都是采用公平策略(根據(jù)等待隊(duì)列依次排序等待);而“非公平鎖”在每次嘗試獲取鎖時(shí),都是采用的非公平策略(無視等待隊(duì)列,直接嘗試獲取鎖,如果鎖是空閑的,即可獲取狀態(tài),則獲取鎖)。
1. lock()
lock()在ReentrantLock.java的NonfairSync類中實(shí)現(xiàn),它的源碼如下: final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); }
說明:
lock()會先通過compareAndSet(0, 1)來判斷“鎖”是不是空閑狀態(tài)。是的話,“當(dāng)前線程”直接獲取“鎖”;否則的話,調(diào)用acquire(1)獲取鎖。
(01) compareAndSetState()是CAS函數(shù),它的作用是比較并設(shè)置當(dāng)前鎖的狀態(tài)。若鎖的狀態(tài)值為0,則設(shè)置鎖的狀態(tài)值為1。
(02) setExclusiveOwnerThread(Thread.currentThread())的作用是,設(shè)置“當(dāng)前線程”為“鎖”的持有者。
“公平鎖”和“非公平鎖”關(guān)于lock()的對比
- 公平鎖 -- 公平鎖的lock()函數(shù),會直接調(diào)用acquire(1)。
- 非公平鎖 -- 非公平鎖會先判斷當(dāng)前鎖的狀態(tài)是不是空閑,是的話,就不排隊(duì),而是直接獲取鎖。
2. acquire()
acquire()在AQS中實(shí)現(xiàn)的,它的源碼如下:
public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }
(01) “當(dāng)前線程”首先通過tryAcquire()嘗試獲取鎖。獲取成功的話,直接返回;嘗試失敗的話,進(jìn)入到等待隊(duì)列依次排序,然后獲取鎖。
(02) “當(dāng)前線程”嘗試失敗的情況下,會先通過addWaiter(Node.EXCLUSIVE)來將“當(dāng)前線程”加入到"CLH隊(duì)列(非阻塞的FIFO隊(duì)列)"末尾。
(03) 然后,調(diào)用acquireQueued()獲取鎖。在acquireQueued()中,當(dāng)前線程會等待它在“CLH隊(duì)列”中前面的所有線程執(zhí)行并釋放鎖之后,才能獲取鎖并返回。如果“當(dāng)前線程”在休眠等待過程中被中斷過,則調(diào)用selfInterrupt()來自己產(chǎn)生一個(gè)中斷。
“公平鎖”和“非公平鎖”關(guān)于acquire()的對比
公平鎖和非公平鎖,只有tryAcquire()函數(shù)的實(shí)現(xiàn)不同;即它們嘗試獲取鎖的機(jī)制不同。這就是我們所說的“它們獲取鎖策略的不同所在之處”!
非公平鎖的tryAcquire()在ReentrantLock.java的NonfairSync類中實(shí)現(xiàn),源碼如下:
protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); }
nonfairTryAcquire()在ReentrantLock.java的Sync類中實(shí)現(xiàn),源碼如下:
final boolean nonfairTryAcquire(int acquires) { // 獲取“當(dāng)前線程” final Thread current = Thread.currentThread(); // 獲取“鎖”的狀態(tài) int c = getState(); // c=0意味著“鎖沒有被任何線程鎖擁有” if (c == 0) { // 若“鎖沒有被任何線程鎖擁有”,則通過CAS函數(shù)設(shè)置“鎖”的狀態(tài)為acquires。 // 同時(shí),設(shè)置“當(dāng)前線程”為鎖的持有者。 if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } else if (current == getExclusiveOwnerThread()) { // 如果“鎖”的持有者已經(jīng)是“當(dāng)前線程”, // 則將更新鎖的狀態(tài)。 int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; }
說明:
根據(jù)代碼,我們可以分析出,tryAcquire()的作用就是嘗試去獲取鎖。
(01) 如果“鎖”沒有被任何線程擁有,則通過CAS函數(shù)設(shè)置“鎖”的狀態(tài)為acquires,同時(shí),設(shè)置“當(dāng)前線程”為鎖的持有者,然后返回true。
(02) 如果“鎖”的持有者已經(jīng)是當(dāng)前線程,則將更新鎖的狀態(tài)即可。
(03) 如果不術(shù)語上面的兩種情況,則認(rèn)為嘗試失敗。
“公平鎖”和“非公平鎖”關(guān)于tryAcquire()的對比
公平鎖和非公平鎖,它們嘗試獲取鎖的方式不同。
公平鎖在嘗試獲取鎖時(shí),即使“鎖”沒有被任何線程鎖持有,它也會判斷自己是不是CLH等待隊(duì)列的表頭;是的話,才獲取鎖。
而非公平鎖在嘗試獲取鎖時(shí),如果“鎖”沒有被任何線程持有,則不管它在CLH隊(duì)列的何處,它都直接獲取鎖。
釋放非公平鎖(基于JDK1.7.0_40)
非公平鎖和公平鎖在釋放鎖的方法和策略上是一樣的。
總結(jié)
公平鎖和非公平鎖的區(qū)別,是在獲取鎖的機(jī)制上的區(qū)別。表現(xiàn)在,在嘗試獲取鎖時(shí) —— 公平鎖,只有在當(dāng)前線程是CLH等待隊(duì)列的表頭時(shí),才獲取鎖;而非公平鎖,只要當(dāng)前鎖處于空閑狀態(tài),則直接獲取鎖,而不管CLH等待隊(duì)列中的順序。
只有當(dāng)非公平鎖嘗試獲取鎖失敗的時(shí)候,它才會像公平鎖一樣,進(jìn)入CLH等待隊(duì)列排序等待。
相關(guān)文章
Java實(shí)戰(zhàn)之小米交易商城系統(tǒng)的實(shí)現(xiàn)
這篇文章將利用Java實(shí)現(xiàn)小米交易商城系統(tǒng),文中采用的技術(shù)有:JSP?、Spring、SpringMVC、MyBatis等,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2022-04-04面試題:Java 實(shí)現(xiàn)查找旋轉(zhuǎn)數(shù)組的最小數(shù)字
這篇文章主要介紹了Java 實(shí)現(xiàn)查找旋轉(zhuǎn)數(shù)組的最小數(shù)字,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-07-07關(guān)于Android觸摸事件分發(fā)的原理詳析
觸摸事件分發(fā)機(jī)制一直以來都是Android中比較重要的一大塊,自定義view,各種復(fù)雜的自定義手勢交互都與觸摸事件分發(fā)機(jī)制關(guān)系密,下面這篇文章主要給大家介紹了關(guān)于Android觸摸事件分發(fā)原理的相關(guān)資料,需要的朋友可以參考下2022-01-01Mybatis?Web中的數(shù)據(jù)庫操作方法舉例詳解
Mybatis是一款優(yōu)秀的持久化框架,用于簡化JDBC的開發(fā),下面這篇文章主要給大家介紹了關(guān)于Mybatis?Web中數(shù)據(jù)庫操作方法的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-09-09在idea中創(chuàng)建SpringBoot項(xiàng)目
這篇文章主要介紹了在idea中創(chuàng)建SpringBoot項(xiàng)目,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-07-07在java中main函數(shù)如何調(diào)用外部非static方法
這篇文章主要介紹了在java中main函數(shù)如何調(diào)用外部非static方法,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12