AQS 全稱 AbstractQueuedSynchronizer 中文翻譯同步器 同步器是java中各種鎖實(shí)現(xiàn)的基礎(chǔ),非常重用的 。比如我們線程池里面的Worker 類 我們的重入鎖ReentrantLock,信號(hào)量Semaphore,CountDownLatch 等
- Java-AQS同步器 源碼解讀<一>獨(dú)占鎖加鎖
- Java-AQS同步器 源碼解讀<二>獨(dú)占鎖解鎖
- Java-AQS同步器 源碼解讀<三>共享鎖
- Java-AQS同步器 源碼解讀<四>-條件隊(duì)列上
- Java-AQS同步器 源碼解讀<五>-條件隊(duì)列下
我們一步步的來(lái)看 是怎么實(shí)現(xiàn)的
首先 我們先看下 這個(gè)類文件
abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer
implements java.io.Serializable
從文件中我們看出 AbstractQueuedSynchronizer是個(gè)抽象類繼承了AbstractOwnableSynchronizer抽象類
那我們就去看看AbstractOwnableSynchronizer有什么
AbstractOwnableSynchronizer
public abstract class AbstractOwnableSynchronizer
implements java.io.Serializable {
/** Use serial ID even though all fields transient. */
private static final long serialVersionUID = 3737899427754241961L;
/**
* 構(gòu)造器
*/
protected AbstractOwnableSynchronizer() { }
/**
* The current owner of exclusive mode synchronization.
* 從上面的英文翻譯 和下面字段的命名 我們能知道 這個(gè)是一個(gè)線程對(duì)象
* 是獨(dú)占鎖模式下 同步器的當(dāng)前擁有者線程
*/
private transient Thread exclusiveOwnerThread;
/**
* 設(shè)置 獨(dú)占鎖 同步器的擁著線程 沒(méi)什么好說(shuō)的
*/
protected final void setExclusiveOwnerThread(Thread thread) {
exclusiveOwnerThread = thread;
}
/**
* 獲取當(dāng)前 同步器的擁著線程 也沒(méi)什么
*/
protected final Thread getExclusiveOwnerThread() {
return exclusiveOwnerThread;
}
從以上的代碼中 我們可以分析得到 AQS 基礎(chǔ)這個(gè)類 是為了 得到獨(dú)占鎖模式擁有鎖的線程 方便監(jiān)控
AbstractQueuedSynchronizer
那看完 上面的代碼 那我們進(jìn)入AbstractQueuedSynchronizer 里面看下 這個(gè)類里面又有什么
從源碼中 我們可以將AQS的內(nèi)部屬性分為4類
- 同步器的簡(jiǎn)單屬性,
- 同步隊(duì)列屬性,
- 條件隊(duì)列屬性,
- 公用的Node類,和一個(gè)ConditionObject類
一個(gè)一個(gè)來(lái)看吧
先看Node這個(gè)類 這個(gè)類很重要 它即是同步隊(duì)列的節(jié)點(diǎn) 也是條件隊(duì)列的節(jié)點(diǎn)
AQS 內(nèi)部Node
/**
* 等待隊(duì)列的節(jié)點(diǎn)類,通過(guò)Node 可以實(shí)現(xiàn)2個(gè)隊(duì)列 一個(gè)是線程同步隊(duì)列(雙向隊(duì)列) 一個(gè)是條件線程隊(duì)列(單向隊(duì)列)
*/
static final class Node {
/**
* 標(biāo)識(shí)這個(gè)節(jié)點(diǎn)用于共享模式
* Marker to indicate a node is waiting in shared mode
*/
static final AbstractQueuedSynchronizer.Node SHARED = new AbstractQueuedSynchronizer.Node();
/**
* 標(biāo)識(shí)這個(gè)節(jié)點(diǎn)用于 獨(dú)占模式(排它 反正一個(gè)意思)
* Marker to indicate a node is waiting in exclusive mode
*/
static final AbstractQueuedSynchronizer.Node EXCLUSIVE = null;
/** 下面是 waitStatus 的幾個(gè)常量值 */
/**
* 表明等待線程已經(jīng)取消
* waitStatus value to indicate thread has cancelled
*/
static final int CANCELLED = 1;
/**
* 表述如果當(dāng)前節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)狀態(tài)是 SIGNAL 那么就可以阻塞當(dāng)前自己的線程 不用去爭(zhēng)搶資源了 沒(méi)用 不然會(huì)一直嘗試去獲取資源
* waitStatus value to indicate successor's thread needs unparking
*/
static final int SIGNAL = -1;
/**
* 線程在條件隊(duì)列中等待
* waitStatus value to indicate thread is waiting on condition
*/
static final int CONDITION = -2;
/**
* 共享模式下 無(wú)條件傳播 該狀態(tài)的進(jìn)程處于可運(yùn)行狀態(tài)
* waitStatus value to indicate the next acquireShared should
* unconditionally propagate
*/
static final int PROPAGATE = -3;
/**
* 當(dāng)前node 狀態(tài)
*/
volatile int waitStatus;
/**
* 獨(dú)占模式下 節(jié)點(diǎn)指向的上一個(gè)節(jié)點(diǎn)
*/
volatile AbstractQueuedSynchronizer.Node prev;
/**
* 獨(dú)占模式下 節(jié)點(diǎn)指向的下一個(gè)節(jié)點(diǎn)
*/
volatile AbstractQueuedSynchronizer.Node next;
/**
* 入隊(duì)時(shí)的線程
* The thread that enqueued this node. Initialized on
* construction and nulled out after use.
*/
volatile Thread thread;
/**
* condition 條件隊(duì)列中的后繼節(jié)點(diǎn)
*/
AbstractQueuedSynchronizer.Node nextWaiter;
/**
* Returns true if node is waiting in shared mode.
*/
final boolean isShared() {
return nextWaiter == SHARED;
}
/**
* 返回當(dāng)前節(jié)點(diǎn)的前驅(qū)節(jié)點(diǎn)
*
* @return the predecessor of this node
*/
final AbstractQueuedSynchronizer.Node predecessor() throws NullPointerException {
AbstractQueuedSynchronizer.Node p = prev;
if (p == null)
throw new NullPointerException();
else
return p;
}
Node() { // Used to establish initial head or SHARED marker
}
/**
* 用于addWaiter
*/
Node(Thread thread, AbstractQueuedSynchronizer.Node mode) {
this.nextWaiter = mode;
this.thread = thread;
}
/**
* 用于Condition
*/
Node(Thread thread, int waitStatus) {
this.waitStatus = waitStatus;
this.thread = thread;
}
}
AQS 實(shí)例屬性
看完了 Node 節(jié)點(diǎn) 我看看下AQS 本身的實(shí)例屬性 有哪些
/**
* 同步隊(duì)列的頭 初始化 或者setHead方法可修改
*/
private transient volatile Node head;
/**
* 同步隊(duì)列的尾節(jié)點(diǎn) 通過(guò)enq方法去修改尾節(jié)點(diǎn) 后面會(huì)分析到
*/
private transient volatile Node tail;
/**
* 同步器的狀態(tài) 這里 可以去 去看下 Semaphore 這個(gè)類 我們初始化的時(shí)候 實(shí)際
上就是調(diào)用的setState 方法 給同步器的狀態(tài)賦值的 每個(gè)線程獲取的時(shí)候都會(huì)去消 耗這個(gè)值 達(dá)到控制并發(fā)效果
*/
private volatile int state;
/**
* 獲取同步器狀態(tài)
*/
protected final int getState() {
return state;
}
/**
* 同步器狀態(tài)賦值
*/
protected final void setState(int newState) {
state = newState;
}
看完了 上面的2中模式 解鎖下獨(dú)占和共享什么意思吧
獨(dú)占的意思的同一時(shí)刻 只能有一個(gè)線程可以獲得鎖 其余的都排隊(duì)阻塞,釋放資源的時(shí)候也只有線程可以釋放 比如重入鎖ReentrantLock
共享就是允許多個(gè)線程獲得同一個(gè)鎖,并且可以設(shè)置獲取鎖的線程數(shù)量 比如我 用Semaphore初始狀態(tài)設(shè)置為4 每個(gè)線程獲取2個(gè) 那同時(shí)可以有2個(gè)線程獲取鎖
AQS 獨(dú)占鎖
看完了上面的一些接受 下面我們來(lái)跟著代碼去分析下獨(dú)占鎖 是怎么實(shí)現(xiàn)的
獨(dú)占鎖 加鎖
-
acquire方法
為什么首先 我們要看這個(gè)方法呢,因?yàn)檫@是鎖獲取資源的入口,那我們就看下代碼,用ReentrantLock來(lái)舉例看看
我們使用ReentrantLock 開(kāi)始加鎖
public void lock() {
sync.lock();
}
我們看下sync.lock 是什么
abstract static class Sync extends AbstractQueuedSynchronizer {
/**
* Performs {@link Lock#lock}. The main reason for subclassing
* is to allow fast path for nonfair version.
*/
abstract void lock();
......
}
可以看到sync的lock 方法也是個(gè)抽象方法 應(yīng)該是Sync的子類去實(shí)現(xiàn)的
那我們就看下ReentrantLock的構(gòu)造方法
/**
* Creates an instance of {@code ReentrantLock}.
* This is equivalent to using {@code ReentrantLock(false)}.
*/
public ReentrantLock() {
sync = new NonfairSync();
}
其中得到ReentrantLock 默認(rèn)構(gòu)造函數(shù)中 sync的實(shí)現(xiàn)是NonfairSync公平鎖,那我們繼續(xù)看NonfairSync這個(gè)類
/**
* Sync object for non-fair locks
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
}
如果 我們找到了Sync的抽象方法lock 在子類中的實(shí)現(xiàn),其實(shí)就是執(zhí)行了acquire 方法
acquire方法在那呢 ?
FairSync 繼承了內(nèi)部抽象類 Sync類 而從上面的截取的代碼中
我們看到Sync類其實(shí)就繼承了AbstractQueuedSynchronizer 類 這樣最終我們會(huì)定位到AQS類中acquire方法
那下面我們就來(lái)看下acquire 這個(gè)方法
/*
*以獨(dú)占鎖的方式 去獲取資源 響應(yīng)中斷
*/
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
- tryAcquire(arg) 方法
protected boolean tryAcquire(int arg) {
throw new UnsupportedOperationException();
}
首先我們看到這個(gè)AQS里面 雖然寫(xiě)了tryAcquire方法 但是 拋出一個(gè)異常,為什么要這么做呢 其實(shí)JDK 作者 是為了方便開(kāi)發(fā)者 我什么這么說(shuō)呢 因?yàn)锳QS是個(gè)抽象類 這個(gè)方法其實(shí)可以寫(xiě)成抽象方法 讓子類來(lái)實(shí)現(xiàn) 但是這帶來(lái)一個(gè)問(wèn)題 因?yàn)锳QS是很多鎖實(shí)現(xiàn)的基礎(chǔ) 如果寫(xiě)成抽象方法 子類就必須實(shí)現(xiàn) 但是可能有些鎖 并不需要實(shí)現(xiàn)這個(gè)方法 沒(méi)用。所以AQS里面這么去寫(xiě),是OK的,因?yàn)橐褂玫倪@個(gè)功能的鎖 必須去實(shí)現(xiàn)重寫(xiě)這個(gè)方法,不讓就報(bào)錯(cuò) ,不要使用到這個(gè)方法的子類 不用管。這樣的思想 我們可以去參考 在以后得開(kāi)發(fā)中!
那我們?nèi)タ聪翿eentrantLock 類中是否是這樣做的
看下代碼:

從上面的截圖中 我們可以看到 確實(shí)是實(shí)現(xiàn)了的 ReentrantLock 有一個(gè)抽象類Sync 2個(gè)靜態(tài)類 且繼承抽象類 Sync 繼承了我們AQS 并且實(shí)現(xiàn)釋放資源的方法,加鎖去獲取資源的方法tryAcquire 分別由2個(gè)子類實(shí)現(xiàn)就 一個(gè)實(shí)現(xiàn)FairSync 公平鎖 一個(gè)實(shí)現(xiàn)NonfairSync非公平鎖
tryAcquire 方法是嘗試以獨(dú)占的方式去獲取資源
具體各個(gè)鎖里面的方法實(shí)現(xiàn) 自己可以去看下 我們還是看下吧ReentrantLock
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
上面的代碼是非公平鎖 實(shí)現(xiàn)的TryAcquire方法的版本 其實(shí)也很好讀懂就是判斷我們之前提到過(guò)的AQS里面的state ,上面我提到過(guò)ReentrantLock 默認(rèn)是非公平鎖,初始化的state值是0,這個(gè)一開(kāi)始用getState 去獲取方法state當(dāng)前的值,如果值等于0,說(shuō)明鎖沒(méi)有其他線程占用,可以獲取鎖,使用CAS原子操作State 新增1,如果CAS 成功就設(shè)置當(dāng)前鎖的所屬的線程 這個(gè)一開(kāi)始我描述過(guò)AbstractOwnableSynchronizer里面的功能 ,如果獲取的時(shí)候state不為0,就判斷下當(dāng)前的線程是否等于鎖所屬的線程,因?yàn)槭仟?dú)占的 ,如果相等就把State 再次加1,這個(gè)判斷也就是說(shuō) 我們調(diào)了同個(gè)線程多次lock了,這個(gè)時(shí)非公平鎖的代碼,公平鎖的實(shí)現(xiàn)和上面的差不多 就是多了一個(gè)隊(duì)列的判斷,要從阻塞隊(duì)列里面的頭部節(jié)點(diǎn)開(kāi)始一個(gè)個(gè)地排隊(duì)獲取,而非公平鎖就沒(méi)有,只要釋放了 看誰(shuí)先來(lái) 就誰(shuí)先獲取到鎖,看多不公平啊,哈哈!
是否滿足,如果滿足就返回True說(shuō)明獲取到了鎖,不滿足就返回false acquire后面的方法會(huì)繼續(xù)執(zhí)行
好的 我們繼續(xù)回到acquire方法中 如果tryacquire方法返回false 也就是沒(méi)有獲取到鎖,執(zhí)行下一個(gè)方法acquireQueued(addWaiter(Node.EXCLUSIVE), arg) 那進(jìn)入這個(gè)方法的時(shí)候 又先執(zhí)行addWaiter 后執(zhí)行acquireQueued
- addWaiter(Node.EXCLUSIVE)方法
/**
* 這個(gè)方法就是加入當(dāng)前節(jié)點(diǎn)到隊(duì)列的尾節(jié)點(diǎn)
*/
private Node addWaiter(Node mode) {
/*構(gòu)建node 節(jié)點(diǎn) 還記得 我們上面寫(xiě)的方法 用于addWaiter么 可以上面去看下
這里的node 幾點(diǎn)里面的nextWaiter 這個(gè)字段被復(fù)用了,在排他鎖模式下用于記錄鎖類型*/
Node node = new Node(Thread.currentThread(), mode);
/*Try the fast path of enq; backup to full enq on failure
從上面的英文注解上面 我們能得到下面的方法是先嘗試快速加入隊(duì)尾,
成功則返回當(dāng)前節(jié)點(diǎn),如果失敗就進(jìn)入的 enq方法 最后返回節(jié)點(diǎn)*/
Node pred = tail;
if (pred != null) {
//當(dāng)前節(jié)點(diǎn)的頭節(jié)點(diǎn)指向隊(duì)列的尾部節(jié)點(diǎn),相當(dāng)于加入到最后了
node.prev = pred;
//CAS 賦值隊(duì)列尾部節(jié)點(diǎn)
if (compareAndSetTail(pred, node)) {
// 如果成功將尾部節(jié)點(diǎn)的下個(gè)節(jié)點(diǎn)指向我們新加的節(jié)點(diǎn),因?yàn)槭请p向鏈表,所以要互相指一下的
pred.next = node;
return node;
}
}
// 如果 尾部節(jié)點(diǎn)是null 或者CAS賦值尾部節(jié)點(diǎn)失敗,則進(jìn)入enq 方法,其實(shí)就是采用了自旋的方法加入 走我們進(jìn)去看下怎么做的
enq(node);
return node;
}
-enq 方法
老規(guī)矩 上源碼
/*
* 使用自旋的方法 加入尾部節(jié)點(diǎn)
*/
private Node enq(final Node node) {
//無(wú)條件的循環(huán) 自旋 好好理解下這個(gè)方法 其實(shí)循環(huán)只有一個(gè)出口 就是成功加入尾部節(jié)點(diǎn)返回
for (;;) {
Node t = tail;
if (t == null) { // 這邊尾部節(jié)點(diǎn)是null 說(shuō)明整個(gè)隊(duì)列都是空的 必須初始化一下
/*CAS 賦值一個(gè)頭部節(jié)點(diǎn) 如果成功 就頭節(jié)點(diǎn)賦值給尾節(jié)點(diǎn),
也很好理解初始化么 沒(méi)有任何節(jié)點(diǎn),當(dāng)然頭就是尾,尾就是頭,不理解的可以看看 鏈表結(jié)構(gòu)如果CAS失敗,
就不做什么 反正又出不來(lái)這個(gè)循環(huán),就繼續(xù)循壞吧,總會(huì)成功的,不要覺(jué)得這邊會(huì)死循環(huán),因?yàn)榫退鉉AS不成功,
可能是有別的線程修改了值導(dǎo)致的,下次循環(huán)的時(shí)候就走不到這邊了 t也就是尾節(jié)點(diǎn)就不為null了,走到下面的判斷*/
if (compareAndSetHead(new Node()))
tail = head;
} else {
//走呀走 終于到這邊了,看看這部代碼 是不是很熟悉,好好想想,往上面看看,其實(shí)addWaiter的方法是一樣的,
//只不過(guò)這邊做了自旋操作,保證了一定加入隊(duì)尾成功
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
ok 看到這邊 小伙伴們 不知道有沒(méi)有暈哈,不管怎么樣,革命尚未成功,繼續(xù)哈,好的 我們回到acquire中
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
上面我們看了tryAcquire方法 和addWaiter方法,那最后我們看下acquireQueued方法是什么 acquireQueued方法的參數(shù)一個(gè)就是addWaiter 返回加入尾部的節(jié)點(diǎn),還有一個(gè)arg是我們各個(gè)實(shí)現(xiàn)鎖方法傳進(jìn)來(lái)的
-acquireQueued方法
/**
* 當(dāng)前節(jié)點(diǎn)加入的隊(duì)尾后,嘗試自旋的方式去獲取資源,
* 這個(gè)方法還有個(gè)作用就是自己的前置節(jié)點(diǎn)變?yōu)镾IGNAL 這樣他自己就能阻塞了
*/
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;//表述是否拿到資源失敗 也就是說(shuō)false表述拿到資源了
try {
//標(biāo)記 是否執(zhí)行中斷 為什么有這個(gè)是因?yàn)榇朔椒](méi)有拋出異常 如果內(nèi)部發(fā)生異常 要通知上一級(jí)調(diào)用,所有有此標(biāo)識(shí)
boolean interrupted = false;
for (;;) {//這邊又是自旋的方法 方法出口只有一個(gè) 就是獲取到資源
/*
P 是當(dāng)前節(jié)點(diǎn)node的前一個(gè)節(jié)點(diǎn) 這邊判斷的意思 是如果當(dāng)前節(jié)點(diǎn)的前一個(gè)節(jié)點(diǎn)就是頭部節(jié)點(diǎn),那就嘗試去獲取鎖資源,
如果能獲取到 說(shuō)明頭節(jié)點(diǎn)已經(jīng)釋放了鎖,那就迅速讓自己成為隊(duì)列的頭部節(jié)點(diǎn),讓之前的頭部節(jié)點(diǎn)next指向null
是為了方便GC的回收,然后賦值failed 為true 表示已經(jīng)獲取到資源,并且返回中斷狀態(tài)
*/
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
//如果P不是head節(jié)點(diǎn)或者是head節(jié)點(diǎn)但是嘗試獲取資源失敗,說(shuō)明鎖資源還沒(méi)被釋放,那就執(zhí)行到這邊
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
那我們?cè)谶M(jìn)入shouldParkAfterFailedAcquire 方法中看看 是什么
-shouldParkAfterFailedAcquire 方法
/**
* 更新prev節(jié)點(diǎn)狀態(tài) ,并根據(jù)prev節(jié)點(diǎn)狀態(tài)判斷是否自己當(dāng)前線程需要阻塞
*/
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;// node的prev節(jié)點(diǎn)的狀態(tài)
if (ws == Node.SIGNAL)
// 如果SIGNAL 就返回true 就會(huì)執(zhí)行到parkAndCheckInterrupt方法里面
return true;
if (ws > 0) {
/*
* 如果ws 大于0 這里是只能為1,如果是1說(shuō)明線程已經(jīng)取消,相當(dāng)于無(wú)效節(jié)點(diǎn)
* 者說(shuō)明 當(dāng)前node 節(jié)點(diǎn)加入到了一個(gè)無(wú)效節(jié)點(diǎn)后面,那這個(gè)必須處理一下
node.prev = pred = pred.prev
* 這個(gè)操作 我們拆解下來(lái)看,下看 pred = pred.prev這個(gè)的意思是把prev節(jié)點(diǎn)的prev*節(jié)點(diǎn) 賦值給prev節(jié)點(diǎn)
*后面再看 node.prev = pred 聯(lián)合 剛才的賦值 這個(gè)的意思就是把prev節(jié)點(diǎn)的prev節(jié)點(diǎn)和node關(guān)聯(lián)起來(lái),
*原因我上面也說(shuō)了因?yàn)閜re節(jié)點(diǎn)線程取消了,所以node節(jié)點(diǎn)不能指向pre節(jié)點(diǎn) 只能一個(gè)一個(gè)的往前找,
*找到waitStatus 小于或者等于0的結(jié)束循環(huán)最后再把找到的pre節(jié)點(diǎn)執(zhí)行node節(jié)點(diǎn) ,這樣就跳過(guò)了所有無(wú)效的節(jié)點(diǎn)
*/
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
/*
*這邊的操作就是把pred 節(jié)點(diǎn)的狀態(tài)設(shè)置為SIGNAL,這樣返回false 這樣可以返回到上面的自旋中
*再次執(zhí)行一次,如果還是獲取不到鎖,那么又回到當(dāng)前的shouldParkAfterFailedAcquire方法 執(zhí)行到方法最上面的判斷
*/
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
-parkAndCheckInterrupt方法
回到剛才 如果shouldParkAfterFailedAcquire方法返回true 那么就會(huì)執(zhí)行parkAndCheckInterrupt方法
這個(gè)方法很簡(jiǎn)單
/**
* Convenience method to park and then check if interrupted
* @return {@code true} if interrupted
*/
private final boolean parkAndCheckInterrupt() {
/*
* 這邊線程阻塞,只有2中方式喚醒當(dāng)前線程,
* 一種方式就是 當(dāng)前線程發(fā)生中斷
* 另外一個(gè)情況就是 資源釋放的時(shí)候會(huì)調(diào)unpark 方法 喚醒當(dāng)前的線程 這個(gè)會(huì)在下一篇會(huì)講到
*/
LockSupport.park(this);
return Thread.interrupted();
}
沒(méi)什么好說(shuō)的 就是阻塞當(dāng)前線程,并且檢查當(dāng)前線程有沒(méi)有過(guò)中斷 返回 正常的話 只有release釋放資源后 會(huì)喚醒線程 但是線程發(fā)生中斷也是可以的 所以這邊要堅(jiān)持下 是那種情況 喚醒當(dāng)前線程的方式 并返回
最后的最后我們?cè)俅位氐絼偛诺姆椒?/p>
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
最后這邊 currentThread做出線程中斷 如果上面都返回true的話
static void selfInterrupt() {
Thread.currentThread().interrupt();
}
不知道 大家有沒(méi)有了解acquire 怎么去實(shí)現(xiàn)獲取資源的了
如果還是不知道 AQS里面的獨(dú)占鎖怎么加鎖的 最后做下簡(jiǎn)短的總結(jié):
1.首先第一步 用tryAcquire方法嘗試去獲取資源 此方法由各個(gè)繼承類重寫(xiě),如果成功就直接返回 獲取鎖成功,如果失敗 則進(jìn)入步驟2
2.進(jìn)入addWaiter方法 這個(gè)方法主要做的就是把當(dāng)前的線程包裝成node節(jié)點(diǎn)放入阻塞隊(duì)列的隊(duì)尾,里面有enq方法里面有自旋的操作
3.然后進(jìn)入acquireQueued方法,入?yún)⒁皇莂ddWaiter方法返回的no的節(jié)點(diǎn),入?yún)⒍褪莂cquire 方法的參數(shù)arg,因?yàn)槔锩孢€要調(diào)用tryAcquire方法,所以此參數(shù)要傳的,這個(gè)方法主要做的就是 嘗試自旋去獲取資源,但是嘗試獲取資源也是條件的 就是當(dāng)前node節(jié)點(diǎn)的prev節(jié)點(diǎn)是head,這樣就避免了無(wú)腦去循環(huán)去獲取資源,這個(gè)方法里面還做了一個(gè)事情 就是判斷下 如果當(dāng)前node 節(jié)點(diǎn)的prev節(jié)點(diǎn) waitStatus 如果是SIGNAL 那就直接執(zhí)行下面的parkAndCheckInterrupt方法去阻塞當(dāng)前線程,為什么會(huì)這么寫(xiě)呢,因?yàn)槿绻?dāng)前節(jié)點(diǎn)狀態(tài)是SIGNAL 說(shuō)明自己已經(jīng)獲取過(guò)鎖,并且沒(méi)獲取到,所以后面的節(jié)點(diǎn) 就不要再去獲取了 直接阻塞吧!
4.最后 如果阻塞的線程 有中斷,那會(huì)執(zhí)行到最后一步selfInterrupt中,就是做出線程中斷,好讓當(dāng)前的線程 后面的方法 知道這個(gè)中斷,并做出回應(yīng),如果不清楚這個(gè)的話 就要好好去了解下線程的interrupt 的作用 和三個(gè)常用的方法
好的簡(jiǎn)單的總結(jié)完畢,如果還是不了解 自己一遍看著我的解鎖一個(gè)看著源碼,自己理解下,我相信一定會(huì)有收獲的!加油!