java面試JDK8?new?ReentrantLock()加鎖流程解析
new ReentrantLock() 加鎖流程
//默認(rèn)執(zhí)行NonfairSync.lock(); final void lock() { //cas 0 -> 1 ,如果操作成功,將當(dāng)前線(xiàn)程設(shè)置為獨(dú)占線(xiàn)程 if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else //如果操作失敗 acquire(1); }
public final void acquire(int arg) { //tryAcquire(arg)嘗試獲取鎖,如果獲取鎖失敗返回false,否則返回true if (!tryAcquire(arg) && //嘗試獲得鎖,如果當(dāng)前線(xiàn)程被中斷 返回 true,否則返回false acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) //獲得鎖失敗,且當(dāng)前線(xiàn)程的中斷狀態(tài)為true,則重新去嘗試 selfInterrupt(); }
tryAcquire()
tryAcquire()最終默認(rèn)調(diào)用ReentrantLock.NonfairSync.nonfairTryAcquire();
final boolean nonfairTryAcquire(int acquires) { //獲取當(dāng)前線(xiàn)程 final Thread current = Thread.currentThread(); //獲取state值 int c = getState(); //0 代表沒(méi)有線(xiàn)程占用鎖 if (c == 0) { //cas 將 0 改為 1 if (compareAndSetState(0, acquires)) { //cas 成功之后 將獨(dú)占線(xiàn)程改為當(dāng)前線(xiàn)程 setExclusiveOwnerThread(current); //返回成功 return true; } } //如果有線(xiàn)程獲取當(dāng)前線(xiàn)程(也就是當(dāng)前線(xiàn)程是獨(dú)占線(xiàn)程) else if (current == getExclusiveOwnerThread()) { //state值加1 int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); //保存新的state值 setState(nextc); //返回true return true; } //否則,就返回false return false; }
AbstractQueuedSynchronizer.addWaiter(Node.EXCLUSIVE)
解析
private Node addWaiter(Node mode) { Node node = new Node(Thread.currentThread(), mode); //尾節(jié)點(diǎn)賦值給pred; Node pred = tail; //尾節(jié)點(diǎn)不為空 if (pred != null) { //當(dāng)前的節(jié)點(diǎn)prev指針指向現(xiàn)在的尾節(jié)點(diǎn) node.prev = pred; //cas 將當(dāng)前尾節(jié)點(diǎn) 替換為 node節(jié)點(diǎn) if (compareAndSetTail(pred, node)) { //當(dāng)前尾節(jié)點(diǎn)的next指針指向 node節(jié)點(diǎn) pred.next = node; return node; } } //如果尾節(jié)點(diǎn)為空或者cas替換失敗,則執(zhí)行入隊(duì)操作 enq(node); return node; } //入隊(duì)操作:將當(dāng)前節(jié)點(diǎn)設(shè)置為尾節(jié)點(diǎn),并更新當(dāng)前節(jié)點(diǎn)和替換前的尾節(jié)點(diǎn)的指針指向 private Node enq(final Node node) { for (;;) { //把尾節(jié)點(diǎn)賦值給一個(gè)變量 Node t = tail; //如果尾節(jié)點(diǎn)為空 if (t == null) { //新建一個(gè)節(jié)點(diǎn),設(shè)置為頭節(jié)點(diǎn) if (compareAndSetHead(new Node())) //把頭節(jié)點(diǎn)賦值尾節(jié)點(diǎn) tail = head; } else { //如果尾節(jié)點(diǎn)不為空,當(dāng)前節(jié)點(diǎn)的prev指針指向尾節(jié)點(diǎn) node.prev = t; //cas 將當(dāng)前節(jié)點(diǎn)設(shè)置為尾節(jié)點(diǎn) if (compareAndSetTail(t, node)) { //替換前的尾節(jié)點(diǎn)的next指針指向當(dāng)前節(jié)點(diǎn) t.next = node; return t; } } //如果cas 替換尾節(jié)點(diǎn) 失敗,則循環(huán)執(zhí)行,直到成功為止 } }
AbstractQueuedSynchronizer.acquireQueued(addWaiter(Node.EXCLUSIVE), arg);
//已經(jīng)入隊(duì)的非中斷線(xiàn)程再次嘗試獲取鎖 final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { boolean interrupted = false; for (;;) { //獲取當(dāng)前節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)信息 final Node p = node.predecessor(); //如果前一個(gè)節(jié)點(diǎn)信息為頭節(jié)點(diǎn),并且成功獲得鎖 if (p == head && tryAcquire(arg)) { //設(shè)置當(dāng)前節(jié)點(diǎn)為頭節(jié)點(diǎn) setHead(node); p.next = null; // help GC failed = false; //返回當(dāng)前節(jié)點(diǎn)的線(xiàn)程中斷狀態(tài) return interrupted; } //如果當(dāng)前節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)不是頭節(jié)點(diǎn) 或者 獲得鎖失敗,則阻塞當(dāng)前節(jié)點(diǎn)線(xiàn)程等待當(dāng)前節(jié)點(diǎn)的線(xiàn)程被喚醒,并判斷中斷狀態(tài) if (shouldParkAfterFailedAcquire(p, node) && //阻塞當(dāng)前線(xiàn)程,等待當(dāng)前線(xiàn)程被喚醒后,判斷當(dāng)前線(xiàn)程的中斷狀態(tài) parkAndCheckInterrupt()) interrupted = true; } } finally { if (failed) cancelAcquire(node); } }
shouldParkAfterFailedAcquire(p, node)
細(xì)節(jié)如下:
//獲取鎖失敗的線(xiàn)程檢查并更新node中的waitStatus。如果線(xiàn)程應(yīng)該被阻塞返回true。 private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) { //獲取前一個(gè)節(jié)點(diǎn)的等待狀態(tài) int ws = pred.waitStatus; //-1,代表前一個(gè)節(jié)點(diǎn)被阻塞中,需要喚醒 if (ws == Node.SIGNAL) return true; if (ws > 0) { // > 0 代表前一個(gè)節(jié)點(diǎn)被取消,就遞歸往找waitStatus > 0的節(jié)點(diǎn)信息 do { node.prev = pred = pred.prev; } while (pred.waitStatus > 0); //找到后,將此節(jié)點(diǎn)的next指針指向當(dāng)前節(jié)點(diǎn) pred.next = node; } else { /* * waitStatus must be 0 or PROPAGATE. Indicate that we * need a signal, but don't park yet. Caller will need to * retry to make sure it cannot acquire before parking. * waitStatus 必須是0 或者 -3(表示可以共享獲得)。表明我們需要喚醒,但是還沒(méi)有阻塞。調(diào)用者需要重試去保證在阻塞操作之前不能獲取成功 */ //cas 將 前一個(gè)節(jié)點(diǎn)的waitStatus 改為 -1(需要喚醒) compareAndSetWaitStatus(pred, ws, Node.SIGNAL); } //返回false return false; } private final boolean parkAndCheckInterrupt() { //阻塞當(dāng)前線(xiàn)程 LockSupport.park(this); //當(dāng)前線(xiàn)程被喚醒后,判斷當(dāng)前線(xiàn)程的的中斷狀態(tài) //這里有一個(gè)非常重要的知識(shí)點(diǎn):?jiǎn)拘炎枞€(xiàn)程的方式 1.unpark 2.interrupt return Thread.interrupted(); }
以上就是java面試JDK8 new ReentrantLock()加鎖流程解析的詳細(xì)內(nèi)容,更多關(guān)于java JDK8 new ReentrantLock的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Spring rest接口中的LocalDateTime日期類(lèi)型轉(zhuǎn)時(shí)間戳
這篇文章主要介紹了Spring rest接口中的LocalDateTime日期類(lèi)型轉(zhuǎn)時(shí)間戳的方法,Java程序中一般將日期類(lèi)型定義為L(zhǎng)ocalDateTime,數(shù)據(jù)庫(kù)中保存的時(shí)間是0時(shí)區(qū)的時(shí)間2023-03-03SpringCloud Alibaba項(xiàng)目實(shí)戰(zhàn)之nacos-server服務(wù)搭建過(guò)程
Nacos 是阿里巴巴推出來(lái)的一個(gè)新開(kāi)源項(xiàng)目,這是一個(gè)更易于構(gòu)建云原生應(yīng)用的動(dòng)態(tài)服務(wù)發(fā)現(xiàn)、配置管理和服務(wù)管理平臺(tái)。本章節(jié)重點(diǎn)給大家介紹SpringCloud Alibaba項(xiàng)目實(shí)戰(zhàn)之nacos-server服務(wù)搭建過(guò)程,感興趣的朋友一起看看吧2021-06-06Java使用跳轉(zhuǎn)結(jié)構(gòu)實(shí)現(xiàn)隊(duì)列和棧流程詳解
這篇文章主要介紹了Java使用跳轉(zhuǎn)結(jié)構(gòu)實(shí)現(xiàn)隊(duì)列和棧流程,連續(xù)結(jié)構(gòu)和跳轉(zhuǎn)結(jié)構(gòu)是數(shù)據(jù)結(jié)構(gòu)中常見(jiàn)的兩種基本數(shù)據(jù)結(jié)構(gòu),而我們本次的主角棧和隊(duì)列都 既可以使用使用跳轉(zhuǎn)結(jié)構(gòu)實(shí)現(xiàn)也可以使用連續(xù)結(jié)構(gòu)實(shí)現(xiàn)2023-04-04java web response提供文件下載功能的實(shí)例講解
下面小編就為大家分享一篇java web response提供文件下載功能的實(shí)例講解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-01-01SpringBoot使用RestTemplate如何通過(guò)http請(qǐng)求將文件下載到本地
文章介紹了如何通過(guò)編寫(xiě)代碼批量下載文件,解決了沒(méi)有提供批量下載接口的問(wèn)題,首先篩選出需要下載的文件ID,然后通過(guò)后端代碼發(fā)起HTTP請(qǐng)求,將下載的資源寫(xiě)入本地文件中,總結(jié)了實(shí)現(xiàn)方式和注意事項(xiàng),希望能為類(lèi)似任務(wù)提供參考2025-02-02java實(shí)現(xiàn)航班信息查詢(xún)管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)航班信息查詢(xún)管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-12-12java讀取html文件,并獲取body中所有的標(biāo)簽及內(nèi)容的案例
這篇文章主要介紹了java讀取html文件,并獲取body中所有的標(biāo)簽及內(nèi)容的案例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-08-08淺談Java8對(duì)字符串連接的改進(jìn)正確姿勢(shì)
這篇文章主要介紹了Java8:對(duì)字符串連接的改進(jìn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10