Java concurrency之公平鎖(二)_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
釋放公平鎖(基于JDK1.7.0_40)
1. unlock()
unlock()在ReentrantLock.java中實(shí)現(xiàn)的,源碼如下:
public void unlock() { sync.release(1); }
說(shuō)明:
unlock()是解鎖函數(shù),它是通過(guò)AQS的release()函數(shù)來(lái)實(shí)現(xiàn)的。
在這里,“1”的含義和“獲取鎖的函數(shù)acquire(1)的含義”一樣,它是設(shè)置“釋放鎖的狀態(tài)”的參數(shù)。由于“公平鎖”是可重入的,所以對(duì)于同一個(gè)線程,每釋放鎖一次,鎖的狀態(tài)-1。
關(guān)于AQS, ReentrantLock 和 sync的關(guān)系如下:
public class ReentrantLock implements Lock, java.io.Serializable { private final Sync sync; abstract static class Sync extends AbstractQueuedSynchronizer { ... } ... }
從中,我們發(fā)現(xiàn):sync是ReentrantLock.java中的成員對(duì)象,而Sync是AQS的子類(lèi)。
2. release()
release()在AQS中實(shí)現(xiàn)的,源碼如下:
public final boolean release(int arg) { if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; }
說(shuō)明:
release()會(huì)先調(diào)用tryRelease()來(lái)嘗試釋放當(dāng)前線程鎖持有的鎖。成功的話,則喚醒后繼等待線程,并返回true。否則,直接返回false。
3. tryRelease()
tryRelease()在ReentrantLock.java的Sync類(lèi)中實(shí)現(xiàn),源碼如下:
protected final boolean tryRelease(int releases) { // c是本次釋放鎖之后的狀態(tài) int c = getState() - releases; // 如果“當(dāng)前線程”不是“鎖的持有者”,則拋出異常! if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; // 如果“鎖”已經(jīng)被當(dāng)前線程徹底釋放,則設(shè)置“鎖”的持有者為null,即鎖是可獲取狀態(tài)。 if (c == 0) { free = true; setExclusiveOwnerThread(null); } // 設(shè)置當(dāng)前線程的鎖的狀態(tài)。 setState(c); return free; }
說(shuō)明:
tryRelease()的作用是嘗試釋放鎖。
(01) 如果“當(dāng)前線程”不是“鎖的持有者”,則拋出異常。
(02) 如果“當(dāng)前線程”在本次釋放鎖操作之后,對(duì)鎖的擁有狀態(tài)是0(即,當(dāng)前線程徹底釋放該“鎖”),則設(shè)置“鎖”的持有者為null,即鎖是可獲取狀態(tài)。同時(shí),更新當(dāng)前線程的鎖的狀態(tài)為0。
getState(), setState()在前一章已經(jīng)介紹過(guò),這里不再說(shuō)明。
getExclusiveOwnerThread(), setExclusiveOwnerThread()在AQS的父類(lèi)AbstractOwnableSynchronizer.java中定義,源碼如下:
public abstract class AbstractOwnableSynchronizer implements java.io.Serializable { // “鎖”的持有線程 private transient Thread exclusiveOwnerThread; // 設(shè)置“鎖的持有線程”為t protected final void setExclusiveOwnerThread(Thread t) { exclusiveOwnerThread = t; } // 獲取“鎖的持有線程” protected final Thread getExclusiveOwnerThread() { return exclusiveOwnerThread; } ... }
4. unparkSuccessor()
在release()中“當(dāng)前線程”釋放鎖成功的話,會(huì)喚醒當(dāng)前線程的后繼線程。
根據(jù)CLH隊(duì)列的FIFO規(guī)則,“當(dāng)前線程”(即已經(jīng)獲取鎖的線程)肯定是head;如果CLH隊(duì)列非空的話,則喚醒鎖的下一個(gè)等待線程。
下面看看unparkSuccessor()的源碼,它在AQS中實(shí)現(xiàn)。
private void unparkSuccessor(Node node) { // 獲取當(dāng)前線程的狀態(tài) int ws = node.waitStatus; // 如果狀態(tài)<0,則設(shè)置狀態(tài)=0 if (ws < 0) compareAndSetWaitStatus(node, ws, 0); //獲取當(dāng)前節(jié)點(diǎn)的“有效的后繼節(jié)點(diǎn)”,無(wú)效的話,則通過(guò)for循環(huán)進(jìn)行獲取。 // 這里的有效,是指“后繼節(jié)點(diǎn)對(duì)應(yīng)的線程狀態(tài)<=0” Node s = node.next; if (s == null || s.waitStatus > 0) { s = null; for (Node t = tail; t != null && t != node; t = t.prev) if (t.waitStatus <= 0) s = t; } // 喚醒“后繼節(jié)點(diǎn)對(duì)應(yīng)的線程” if (s != null) LockSupport.unpark(s.thread); }
說(shuō)明:
unparkSuccessor()的作用是“喚醒當(dāng)前線程的后繼線程”。后繼線程被喚醒之后,就可以獲取該鎖并恢復(fù)運(yùn)行了。
關(guān)于node.waitStatus的說(shuō)明,請(qǐng)參考“上一章關(guān)于Node類(lèi)的介紹”。
總結(jié)
“釋放鎖”的過(guò)程相對(duì)“獲取鎖”的過(guò)程比較簡(jiǎn)單。釋放鎖時(shí),主要進(jìn)行的操作,是更新當(dāng)前線程對(duì)應(yīng)的鎖的狀態(tài)。如果當(dāng)前線程對(duì)鎖已經(jīng)徹底釋放,則設(shè)置“鎖”的持有線程為null,設(shè)置當(dāng)前線程的狀態(tài)為空,然后喚醒后繼線程。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Java concurrency之非公平鎖_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
- java 線程公平鎖與非公平鎖詳解及實(shí)例代碼
- Java concurrency之公平鎖(一)_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
- Java反射機(jī)制的精髓講解
- Java源碼解析LinkedList
- Java源碼解析HashMap的keySet()方法
- Java正確實(shí)現(xiàn)一個(gè)單例設(shè)計(jì)模式的示例
- Java源碼解析HashMap的tableSizeFor函數(shù)
- Java源碼解析阻塞隊(duì)列ArrayBlockingQueue介紹
- Java線程公平鎖和非公平鎖的差異講解
相關(guān)文章
Java 中ConcurrentHashMap的實(shí)現(xiàn)
本文主要介紹Java 中ConcurrentHashMap的實(shí)現(xiàn),這里整理了詳細(xì)的資料,及簡(jiǎn)單實(shí)例代碼,有興趣的小伙伴可以參考下2016-09-09java實(shí)現(xiàn)OpenGL ES紋理映射的方法
這篇文章主要介紹了java實(shí)現(xiàn)OpenGL ES紋理映射的方法,以實(shí)例形式較為詳細(xì)的分析了紋理映射的實(shí)現(xiàn)技巧,需要的朋友可以參考下2015-06-06java實(shí)現(xiàn)科研信息管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了java科研信息管理系統(tǒng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-02-02OpenFeign實(shí)現(xiàn)遠(yuǎn)程調(diào)用
這篇文章主要為大家詳細(xì)介紹了OpenFeign實(shí)現(xiàn)遠(yuǎn)程調(diào)用,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08一篇文章帶你入門(mén)java網(wǎng)絡(luò)編程
網(wǎng)絡(luò)編程是指編寫(xiě)運(yùn)行在多個(gè)設(shè)備(計(jì)算機(jī))的程序,這些設(shè)備都通過(guò)網(wǎng)絡(luò)連接起來(lái)。本文介紹了一些網(wǎng)絡(luò)編程基礎(chǔ)的概念,并用Java來(lái)實(shí)現(xiàn)TCP和UDP的Socket的編程,來(lái)讓讀者更好的了解其原理2021-08-08劍指Offer之Java算法習(xí)題精講數(shù)組查找與字符串交集
跟著思路走,之后從簡(jiǎn)單題入手,反復(fù)去看,做過(guò)之后可能會(huì)忘記,之后再做一次,記不住就反復(fù)做,反復(fù)尋求思路和規(guī)律,慢慢積累就會(huì)發(fā)現(xiàn)質(zhì)的變化2022-03-03Java實(shí)現(xiàn)解析dcm醫(yī)學(xué)影像文件并提取文件信息的方法示例
這篇文章主要介紹了Java實(shí)現(xiàn)解析dcm醫(yī)學(xué)影像文件并提取文件信息的方法,結(jié)合實(shí)例形式分析了java基于第三方庫(kù)文件針對(duì)dcm醫(yī)學(xué)影像文件的解析操作相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2018-04-04IntelliJ IDEA中新建Java class的解決方案
今天小編就為大家分享一篇關(guān)于IntelliJ IDEA中新建Java class的解決方案,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-10-10SpringBoot實(shí)現(xiàn)RabbitMQ監(jiān)聽(tīng)消息的四種方式
本文主要介紹了SpringBoot實(shí)現(xiàn)RabbitMQ監(jiān)聽(tīng)消息的四種方式,包括@RabbitListener,MessageListener接口,MessageListenerAdapter適配器,@RabbitHandler這幾種,感興趣的可以了解一下2024-05-05