一、作用
簡(jiǎn)單說(shuō):AQS就是在多線程搶奪共享資源的時(shí)候,實(shí)現(xiàn)了統(tǒng)一規(guī)劃資源步悠,確保只有一個(gè)線程搶奪成功,其他的都排隊(duì)的框架
AQS核心思想:如果被請(qǐng)求的共享資源空閑瘫镇,那么當(dāng)前線程設(shè)置為獨(dú)占線程鼎兽,將當(dāng)前資源設(shè)定為鎖定狀態(tài),如果有其他線程也要訪問(wèn)這個(gè)被鎖定的共享資源铣除,那么就需要一套線程阻塞及被喚醒的分配機(jī)制谚咬,aqs是通過(guò)CLH隊(duì)列鎖實(shí)現(xiàn)的,將獲取不到鎖的線程加到隊(duì)列中通孽。
CLH是啥:FIFO雙向隊(duì)列, 如下圖(圖片來(lái)自網(wǎng)絡(luò)):
AQS的CLH實(shí)現(xiàn):
static final class Node {
/** 標(biāo)識(shí)節(jié)點(diǎn)在共享模式下等待*/
static final Node SHARED = new Node();
/** 標(biāo)識(shí)節(jié)點(diǎn)在獨(dú)占模式下等待*/
static final Node EXCLUSIVE = null;
/** waitStatus 當(dāng)前線程被取消 */
static final int CANCELLED = 1;
/** waitStatus 當(dāng)前節(jié)點(diǎn)的后繼節(jié)點(diǎn)包含的線程需要運(yùn)行序宦,也就是unpark */
static final int SIGNAL = -1;
/** waitStatus 表示當(dāng)前節(jié)點(diǎn)在等待condition,也就是在condition隊(duì)列中 */
static final int CONDITION = -2;
/**
* waitStatus 表示當(dāng)前場(chǎng)景下后續(xù)的acquireShared能夠得以執(zhí)行
*/
static final int PROPAGATE = -3;
volatile int waitStatus;
/**
* 節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)
*/
volatile Node prev;
/**
* 節(jié)點(diǎn)的后繼節(jié)點(diǎn)
*/
volatile Node next;
/**
* 當(dāng)前的線程
*/
volatile Thread thread;
/**
* 隊(duì)列中下一個(gè)等待的線程
*/
Node nextWaiter;
/**
* 如果節(jié)點(diǎn)在共享模式下等待,則返回true互捌。
*/
final boolean isShared() {
return nextWaiter == SHARED;
}
/**
* 返回當(dāng)前節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)
*/
final Node predecessor() throws NullPointerException {
Node p = prev;
if (p == null)
throw new NullPointerException();
else
return p;
}
Node() {
}
Node(Thread thread, Node mode) { // Used by addWaiter
this.nextWaiter = mode;
this.thread = thread;
}
Node(Thread thread, int waitStatus) { // Used by Condition
this.waitStatus = waitStatus;
this.thread = thread;
}
}
二潘明、waitStatus 結(jié)點(diǎn)狀態(tài)
- CANCELLED,值為1秕噪,表示當(dāng)前的線程被取消
- SIGNAL钳降,值為-1,表示當(dāng)前節(jié)點(diǎn)的后繼節(jié)點(diǎn)包含的線程需要運(yùn)行腌巾,也就是unpark
- CONDITION遂填,值為-2,表示當(dāng)前節(jié)點(diǎn)在等待condition澈蝙,也就是在condition隊(duì)列中
- PROPAGATE吓坚,值為-3,表示當(dāng)前場(chǎng)景下后續(xù)的acquireShared能夠得以執(zhí)行
- 值為0灯荧,表示當(dāng)前節(jié)點(diǎn)在sync隊(duì)列中礁击,等待著獲取鎖
三、核心acquire 說(shuō)明(此部分相當(dāng)于ReentrantLock.lock()的過(guò)程)
從ReentrantLock的lock開(kāi)始看吧
new ReentrantLock()默認(rèn)構(gòu)造是非公平鎖逗载,是否公平主要取決于是否按順序去爭(zhēng)搶共享資源椒惨。
public void lock() {
sync.lock(); //加鎖開(kāi)始
}
有兩種是實(shí)現(xiàn)一種是公平一種是非公平囚聚,這里是非公平
非公平鎖
/**
* Sync object for non-fair locks
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
//直接cas方式去搶鎖如果搶成功則設(shè)置當(dāng)前新線程為獨(dú)占線程憎茂。(1)
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
公平鎖乳规,區(qū)別就在于嘗試加鎖的時(shí)候,如上(1)非公平鎖在當(dāng)前資源沒(méi)有被任何線程搶占的時(shí)候能直接搶到資源擦秽,公平鎖則會(huì)進(jìn)行hasQueuedPredecessors判斷,也就是嚴(yán)格按照加入隊(duì)列的順序码荔,F(xiàn)IFO。
非公平鎖的性能高于公平鎖的原因:在恢復(fù)一個(gè)被掛起的線程與該線程真正運(yùn)行之間存在著嚴(yán)重的延遲感挥。
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
//判斷head和tail不相等(說(shuō)明有等待線程)并且(head.next為null=>說(shuō)明有線程正在入隊(duì)列的中間狀態(tài)目胡,肯定不是當(dāng)前線程, 因?yàn)橐粋€(gè)線程一個(gè)時(shí)間只能做一件事 或者 head.next.thread不是當(dāng)前線程),主要是防止中間狀態(tài)的時(shí)候?qū)е虏还降囊蛩爻霈F(xiàn)链快,那么我理解非公平的吞吐量肯定更好好于公平的。
public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized
// before tail and on head.next being accurate if the current
// thread is first in queue.
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
第一次CAS失敗進(jìn)入這里
public final void acquire(int arg) {
if (!tryAcquire(arg) && //如果tryAcquire失敗了眉尸,那就該進(jìn)入CLH隊(duì)列中排隊(duì)了域蜗。
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState(); //獲取當(dāng)前狀態(tài)
if (c == 0) {//代表未被占用
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);//設(shè)置為獨(dú)占
return true;
}
}
else if (current == getExclusiveOwnerThread()) { //如果當(dāng)前線程是當(dāng)前獨(dú)占資源的線程
int nextc = c + acquires; //代表重入
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc); //這里說(shuō)明當(dāng)前線程重入幾次就加幾
return true;
}
return false;
}
tryAcquire 執(zhí)行失敗,則進(jìn)入排隊(duì)
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode); //構(gòu)造一個(gè)新的節(jié)點(diǎn)
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
if (pred != null) {
node.prev = pred;//當(dāng)前隊(duì)列尾節(jié)點(diǎn)作為當(dāng)前節(jié)點(diǎn)的頭結(jié)點(diǎn)
if (compareAndSetTail(pred, node)) {//cas 方式設(shè)置當(dāng)前節(jié)點(diǎn)作為隊(duì)列尾節(jié)點(diǎn)
pred.next = node; //設(shè)置之前的尾節(jié)點(diǎn)的后繼節(jié)點(diǎn)為當(dāng)前節(jié)點(diǎn)噪猾。
return node;
}
}
enq(node);//當(dāng)前隊(duì)列不存在霉祸,需要初始化。
return node;
}
隊(duì)列初始化過(guò)程
private Node enq(final Node node) {
for (;;) { //這里多說(shuō)一句 for這種用法和while(true)一致
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))// 各種cas操作
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {//如果有一個(gè)節(jié)點(diǎn)袱蜡,直接把當(dāng)前節(jié)點(diǎn)作為尾節(jié)點(diǎn)
t.next = node;
return t;
}
}
}
}
tryAcquire() 和 addWaiter()獲取資源失敗丝蹭,放入隊(duì)列尾部,則進(jìn)行下一步:
自旋一直try
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true; //標(biāo)識(shí)位 默認(rèn)是true是代表拿到了資源
try {
boolean interrupted = false; //代表是否被中斷過(guò)坪蚁,這個(gè)在parkAndCheckInterrupt里面說(shuō)比較合適
for (;;) {//又自旋
final Node p = node.predecessor();//前驅(qū)節(jié)點(diǎn)
//只有前驅(qū)是頭結(jié)點(diǎn)了奔穿,他才能參與搶資源镜沽,不是老二就都沒(méi)有資格而且只有當(dāng)前頭結(jié)點(diǎn)釋放資源了或者被中斷了他才能搶到。贱田。
if (p == head && tryAcquire(arg)) {//自旋一直去嘗試獲取資源
setHead(node);//獲取到了則將
p.next = null; // help GC 方便GC這個(gè)不用說(shuō)了
failed = false;
return interrupted;
}
//進(jìn)入waiting狀態(tài)缅茉,直到被中斷或者被調(diào)用unpark,詳情看下面的分析
if (shouldParkAfterFailedAcquire(p, node) && //
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
Node.SIGNAL:waitStatus值男摧,指示后續(xù)線程需要取消waiting(也就是unpark或者中斷)
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus; //前驅(qū)節(jié)點(diǎn)的狀態(tài)
if (ws == Node.SIGNAL) //是前驅(qū)節(jié)點(diǎn)就返回true
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
return true;
if (ws > 0) {//說(shuō)明前驅(qū)節(jié)點(diǎn)已經(jīng)被取消了蔬墩,
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
*/
do {
node.prev = pred = pred.prev; //然后就跳過(guò)當(dāng)前無(wú)效節(jié)點(diǎn)去找有效的。
} while (pred.waitStatus > 0);
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.
*/
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);//如果有效設(shè)置前驅(qū)節(jié)點(diǎn)的狀態(tài)為SIGNAL
}
return false;
}
設(shè)置當(dāng)前線程為等待狀態(tài)且看線程是否被中斷過(guò)耗拓,并清除中斷標(biāo)識(shí)拇颅。
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
總結(jié):
- 調(diào)用tryAcquire() 嘗試直接去獲取資源,如果成功則直接返回乔询;
- 沒(méi)成功樟插,則addWaiter() 將該線程加入等待隊(duì)列的尾部,并標(biāo)記為獨(dú)占模式哥谷;
- acquireQueued()讓線程在等待隊(duì)列中處于waiting狀態(tài)岸夯,當(dāng)輪到當(dāng)前線程,也就是當(dāng)前成為頭結(jié)點(diǎn)的后繼節(jié)點(diǎn)们妥,則會(huì)被unpark())會(huì)去嘗試獲取資源猜扮。獲取到資源后才返回。如果在整個(gè)等待過(guò)程中被中斷過(guò)监婶,則返回true旅赢,否則返回false。
- 如果線程在等待過(guò)程中被中斷過(guò)惑惶,哪怕一次煮盼,也是不會(huì)干活的,會(huì)在搶到資源后進(jìn)行selfInterrupt()自己中斷自己带污,有點(diǎn)后置僵控。
四、核心release說(shuō)明(此部分相當(dāng)于ReentrantLock.unlock()的過(guò)程)
release相當(dāng)于acquire的相反操作鱼冀,也就是釋放資源报破,釋放指定量的資源。
public void unlock() {
sync.release(1);
}
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
tryRelease是ReentrantLock中的實(shí)現(xiàn)
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();//也就是當(dāng)前的線程不是此對(duì)象監(jiān)視器的所有者千绪。也就是要在當(dāng)前線程鎖定對(duì)象充易,才能用鎖定的對(duì)象此行這些方法.
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
喚醒等待隊(duì)列中下一個(gè)線程
private void unparkSuccessor(Node node) {
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/
int ws = node.waitStatus;
if (ws < 0)//如果狀態(tài)為負(fù)(即可能需要信號(hào)),則嘗試在預(yù)期信號(hào)時(shí)清除荸型。如果失敗或者狀態(tài)被等待線程更改盹靴,這是正常的。
compareAndSetWaitStatus(node, ws, 0);//head節(jié)點(diǎn)狀態(tài)設(shè)置成0
/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
//unpark的線程保存在后續(xù)節(jié)點(diǎn)中,后者通常只是下一個(gè)節(jié)點(diǎn)稿静。但如果被取消或明顯為空梭冠,則從尾部向后移動(dòng)以找到實(shí)際的未取消的繼承者。
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;
}
if (s != null)
LockSupport.unpark(s.thread);
}
總結(jié):
只有(state=0)才會(huì)將資源徹底釋放自赔。
參考資料
從ReentrantLock的lock開(kāi)始看吧
new ReentrantLock()默認(rèn)構(gòu)造是非公平鎖妈嘹,是否公平主要取決于是否按順序去爭(zhēng)搶共享資源。
public void lock() {
sync.lock(); //加鎖開(kāi)始
}
有兩種是實(shí)現(xiàn)一種是公平一種是非公平绍妨,這里是非公平
非公平鎖
/**
* Sync object for non-fair locks
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
//直接cas方式去搶鎖如果搶成功則設(shè)置當(dāng)前新線程為獨(dú)占線程润脸。(1)
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
公平鎖,區(qū)別就在于嘗試加鎖的時(shí)候他去,如上(1)非公平鎖在當(dāng)前資源沒(méi)有被任何線程搶占的時(shí)候能直接搶到資源毙驯,公平鎖則會(huì)進(jìn)行hasQueuedPredecessors判斷,也就是嚴(yán)格按照加入隊(duì)列的順序,F(xiàn)IFO灾测。
非公平鎖的性能高于公平鎖的原因:在恢復(fù)一個(gè)被掛起的線程與該線程真正運(yùn)行之間存在著嚴(yán)重的延遲爆价。
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
//判斷head和tail不相等(說(shuō)明有等待線程)并且(head.next為null=>說(shuō)明有線程正在入隊(duì)列的中間狀態(tài),肯定不是當(dāng)前線程, 因?yàn)橐粋€(gè)線程一個(gè)時(shí)間只能做一件事 或者 head.next.thread不是當(dāng)前線程)媳搪,主要是防止中間狀態(tài)的時(shí)候?qū)е虏还降囊蛩爻霈F(xiàn)铭段,那么我理解非公平的吞吐量肯定更好好于公平的。
public final boolean hasQueuedPredecessors() {
// The correctness of this depends on head being initialized
// before tail and on head.next being accurate if the current
// thread is first in queue.
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
第一次CAS失敗進(jìn)入這里
public final void acquire(int arg) {
if (!tryAcquire(arg) && //如果tryAcquire失敗了秦爆,那就該進(jìn)入CLH隊(duì)列中排隊(duì)了序愚。
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState(); //獲取當(dāng)前狀態(tài)
if (c == 0) {//代表未被占用
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);//設(shè)置為獨(dú)占
return true;
}
}
else if (current == getExclusiveOwnerThread()) { //如果當(dāng)前線程是當(dāng)前獨(dú)占資源的線程
int nextc = c + acquires; //代表重入
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc); //這里說(shuō)明當(dāng)前線程重入幾次就加幾
return true;
}
return false;
}
tryAcquire 執(zhí)行失敗,則進(jìn)入排隊(duì)
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode); //構(gòu)造一個(gè)新的節(jié)點(diǎn)
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
if (pred != null) {
node.prev = pred;//當(dāng)前隊(duì)列尾節(jié)點(diǎn)作為當(dāng)前節(jié)點(diǎn)的頭結(jié)點(diǎn)
if (compareAndSetTail(pred, node)) {//cas 方式設(shè)置當(dāng)前節(jié)點(diǎn)作為隊(duì)列尾節(jié)點(diǎn)
pred.next = node; //設(shè)置之前的尾節(jié)點(diǎn)的后繼節(jié)點(diǎn)為當(dāng)前節(jié)點(diǎn)等限。
return node;
}
}
enq(node);//當(dāng)前隊(duì)列不存在爸吮,需要初始化。
return node;
}
隊(duì)列初始化過(guò)程
private Node enq(final Node node) {
for (;;) { //這里多說(shuō)一句 for這種用法和while(true)一致
Node t = tail;
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))// 各種cas操作
tail = head;
} else {
node.prev = t;
if (compareAndSetTail(t, node)) {//如果有一個(gè)節(jié)點(diǎn)望门,直接把當(dāng)前節(jié)點(diǎn)作為尾節(jié)點(diǎn)
t.next = node;
return t;
}
}
}
}
tryAcquire() 和 addWaiter()獲取資源失敗形娇,放入隊(duì)列尾部,則進(jìn)行下一步:
自旋一直try
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true; //標(biāo)識(shí)位 默認(rèn)是true是代表拿到了資源
try {
boolean interrupted = false; //代表是否被中斷過(guò)筹误,這個(gè)在parkAndCheckInterrupt里面說(shuō)比較合適
for (;;) {//又自旋
final Node p = node.predecessor();//前驅(qū)節(jié)點(diǎn)
//只有前驅(qū)是頭結(jié)點(diǎn)了桐早,他才能參與搶資源,不是老二就都沒(méi)有資格而且只有當(dāng)前頭結(jié)點(diǎn)釋放資源了或者被中斷了他才能搶到厨剪。勘畔。
if (p == head && tryAcquire(arg)) {//自旋一直去嘗試獲取資源
setHead(node);//獲取到了則將
p.next = null; // help GC 方便GC這個(gè)不用說(shuō)了
failed = false;
return interrupted;
}
//進(jìn)入waiting狀態(tài),直到被中斷或者被調(diào)用unpark丽惶,詳情看下面的分析
if (shouldParkAfterFailedAcquire(p, node) && //
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
Node.SIGNAL:waitStatus值,指示后續(xù)線程需要取消waiting(也就是unpark或者中斷)
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus; //前驅(qū)節(jié)點(diǎn)的狀態(tài)
if (ws == Node.SIGNAL) //是前驅(qū)節(jié)點(diǎn)就返回true
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
return true;
if (ws > 0) {//說(shuō)明前驅(qū)節(jié)點(diǎn)已經(jīng)被取消了爬立,
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
*/
do {
node.prev = pred = pred.prev; //然后就跳過(guò)當(dāng)前無(wú)效節(jié)點(diǎn)去找有效的钾唬。
} while (pred.waitStatus > 0);
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.
*/
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);//如果有效設(shè)置前驅(qū)節(jié)點(diǎn)的狀態(tài)為SIGNAL
}
return false;
}
設(shè)置當(dāng)前線程為等待狀態(tài)且看線程是否被中斷過(guò),并清除中斷標(biāo)識(shí)。
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
總結(jié):
- 調(diào)用tryAcquire() 嘗試直接去獲取資源抡秆,如果成功則直接返回奕巍;
- 沒(méi)成功,則addWaiter() 將該線程加入等待隊(duì)列的尾部儒士,并標(biāo)記為獨(dú)占模式的止;
- acquireQueued()讓線程在等待隊(duì)列中處于waiting狀態(tài),當(dāng)輪到當(dāng)前線程着撩,也就是當(dāng)前成為頭結(jié)點(diǎn)的后繼節(jié)點(diǎn)诅福,則會(huì)被unpark())會(huì)去嘗試獲取資源。獲取到資源后才返回拖叙。如果在整個(gè)等待過(guò)程中被中斷過(guò)氓润,則返回true,否則返回false薯鳍。
- 如果線程在等待過(guò)程中被中斷過(guò)咖气,哪怕一次,也是不會(huì)干活的挖滤,會(huì)在搶到資源后進(jìn)行selfInterrupt()自己中斷自己崩溪,有點(diǎn)后置。
四斩松、核心release說(shuō)明(此部分相當(dāng)于ReentrantLock.unlock()的過(guò)程)
release相當(dāng)于acquire的相反操作伶唯,也就是釋放資源,釋放指定量的資源砸民。
public void unlock() {
sync.release(1);
}
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
tryRelease是ReentrantLock中的實(shí)現(xiàn)
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();//也就是當(dāng)前的線程不是此對(duì)象監(jiān)視器的所有者抵怎。也就是要在當(dāng)前線程鎖定對(duì)象,才能用鎖定的對(duì)象此行這些方法.
boolean free = false;
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
喚醒等待隊(duì)列中下一個(gè)線程
private void unparkSuccessor(Node node) {
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/
int ws = node.waitStatus;
if (ws < 0)//如果狀態(tài)為負(fù)(即可能需要信號(hào))岭参,則嘗試在預(yù)期信號(hào)時(shí)清除反惕。如果失敗或者狀態(tài)被等待線程更改,這是正常的演侯。
compareAndSetWaitStatus(node, ws, 0);//head節(jié)點(diǎn)狀態(tài)設(shè)置成0
/*
* Thread to unpark is held in successor, which is normally
* just the next node. But if cancelled or apparently null,
* traverse backwards from tail to find the actual
* non-cancelled successor.
*/
//unpark的線程保存在后續(xù)節(jié)點(diǎn)中姿染,后者通常只是下一個(gè)節(jié)點(diǎn)。但如果被取消或明顯為空秒际,則從尾部向后移動(dòng)以找到實(shí)際的未取消的繼承者悬赏。
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;
}
if (s != null)
LockSupport.unpark(s.thread);
}
總結(jié):
只有(state=0)才會(huì)將資源徹底釋放。