java面試JDK8?new?ReentrantLock()加鎖流程解析
new ReentrantLock() 加鎖流程
//默認(rèn)執(zhí)行NonfairSync.lock();
final void lock() {
//cas 0 -> 1 ,如果操作成功,將當(dāng)前線程設(shè)置為獨(dú)占線程
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)前線程被中斷 返回 true,否則返回false
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
//獲得鎖失敗,且當(dāng)前線程的中斷狀態(tài)為true,則重新去嘗試
selfInterrupt();
}tryAcquire()
tryAcquire()最終默認(rèn)調(diào)用ReentrantLock.NonfairSync.nonfairTryAcquire();
final boolean nonfairTryAcquire(int acquires) {
//獲取當(dāng)前線程
final Thread current = Thread.currentThread();
//獲取state值
int c = getState();
//0 代表沒有線程占用鎖
if (c == 0) {
//cas 將 0 改為 1
if (compareAndSetState(0, acquires)) {
//cas 成功之后 將獨(dú)占線程改為當(dāng)前線程
setExclusiveOwnerThread(current);
//返回成功
return true;
}
}
//如果有線程獲取當(dāng)前線程(也就是當(dāng)前線程是獨(dú)占線程)
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ì)的非中斷線程再次嘗試獲取鎖
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)的線程中斷狀態(tài)
return interrupted;
}
//如果當(dāng)前節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)不是頭節(jié)點(diǎn) 或者 獲得鎖失敗,則阻塞當(dāng)前節(jié)點(diǎn)線程等待當(dāng)前節(jié)點(diǎn)的線程被喚醒,并判斷中斷狀態(tài)
if (shouldParkAfterFailedAcquire(p, node) &&
//阻塞當(dāng)前線程,等待當(dāng)前線程被喚醒后,判斷當(dāng)前線程的中斷狀態(tài)
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}shouldParkAfterFailedAcquire(p, node)
細(xì)節(jié)如下:
//獲取鎖失敗的線程檢查并更新node中的waitStatus。如果線程應(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(表示可以共享獲得)。表明我們需要喚醒,但是還沒有阻塞。調(diào)用者需要重試去保證在阻塞操作之前不能獲取成功
*/
//cas 將 前一個(gè)節(jié)點(diǎn)的waitStatus 改為 -1(需要喚醒)
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
//返回false
return false;
}
private final boolean parkAndCheckInterrupt() {
//阻塞當(dāng)前線程
LockSupport.park(this);
//當(dāng)前線程被喚醒后,判斷當(dāng)前線程的的中斷狀態(tài)
//這里有一個(gè)非常重要的知識(shí)點(diǎ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)文章
Idea2020.2創(chuàng)建JavaWeb項(xiàng)目(部署Tomcat)方法詳解
這篇文章主要介紹了Idea2020.2創(chuàng)建JavaWeb項(xiàng)目(部署Tomcat)方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08
Java實(shí)現(xiàn)拖拽文件上傳dropzone.js的簡單使用示例代碼
本篇文章主要介紹了Java實(shí)現(xiàn)拖拽文件上傳dropzone.js的簡單使用示例代碼,具有一定的參考價(jià)值,有興趣的可以了解一下2017-07-07
淺談Java并發(fā)編程之synchronized有序性誤區(qū)
本文主要介紹了淺談Java并發(fā)編程之synchronized有序性誤區(qū),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2026-02-02
淺談java中String StringBuffer StringBuilder的區(qū)別
下面小編就為大家?guī)硪黄獪\談java中String StringBuffer StringBuilder的區(qū)別。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2016-06-06
Java字符流和字節(jié)流對(duì)文件操作的區(qū)別
本篇文章主要介紹了Java的IO流分為字符流(Reader,Writer)和字節(jié)流(InputStream,OutputStream),字節(jié)流顧名思義字節(jié)流就是將文件的內(nèi)容讀取到字節(jié)數(shù)組,對(duì)初學(xué)者很有用,有需要的朋友可以了解一下。2016-10-10

