Reentrantlock是併發包中可重入的獨佔鎖,只能有一個線程佔有鎖,鎖的獲取和釋放是基於AQS(AbstractQueuedSynchronized)實現的, 有公平和不公平兩種獲取鎖的實現方式。Reentranlock 中有一個內部抽象類Sync繼承自AbstractQueuedSynchronized, 主要是它來實現鎖獲取和釋放的功能,Sync 在ReentrantLock中有兩種實現類:NonfairSync(非公平獲取鎖)、FairSync(公平獲取鎖), Reentrantlock支持Condition,AQS中有同步隊列和條件隊列,不清楚的,能夠看下個人另外一篇AbstractQueuedSynchronized的源碼分析juejin.im/post/5d0b3b…。java
//獨佔鎖的接口,如下方法在下面都會詳細的介紹
public interface Lock {
//加鎖,不支持中斷
void lock();
//加鎖,支持中斷,拋出中斷異常
void lockInterruptibly() throws InterruptedException;
//嘗試加鎖,不支持中斷
boolean tryLock();
//在超時時間內獲取鎖
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
//解鎖
void unlock();
//獲取條件變量Condition
Condition newCondition();
}複製代碼
//Reentrantlock鎖的獲取和釋放都是基於Sync,Sync在ReentrantLock中有兩種實現類:NonfairSync(非公平獲取鎖)、FairSync(公平獲取鎖),下面會詳細介紹Sync
private final Sync sync;複製代碼
//無參構造函數,建立ReentrantLock實例,建立非公平的獲取鎖NonfairSync實例屬性
public ReentrantLock() {sync = new NonfairSync();}
/** * 根據傳入fair參數,建立非公平的獲取鎖NonfairSync實例或者公平的獲取鎖FairSync實例屬性 * * @param fair {@code true} 建立FairSync實例屬性,false建立NonfairSync實例屬性 */
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
複製代碼
//AbstractQueuedSynchronizer的實現類,鎖的獲取和釋放都是基於Sync,對AbstractQueuedSynchronizer不清楚的,能夠看下另外一篇AbstractQueuedSynchronizer源碼分析
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
//抽象方法,由NonfairSync和FairSync進行實現,公平的獲取鎖,仍是非公平的獲取鎖
abstract void lock();
//在NonfairSync中使用到,非公平的獲取鎖
//@param acquires 要獲取的鎖數
final boolean nonfairTryAcquire(int acquires) {
//獲取當前要加鎖的線程
final Thread current = Thread.currentThread();
//獲取鎖的狀態,即AQS的屬性state值
int c = getState();
//若是鎖的狀態等於0,表示處於無鎖狀態
if (c == 0) {
//使用CAS更新鎖狀態,將鎖狀態更新成要獲取的鎖數
if (compareAndSetState(0, acquires)) {
//若是CAS更新鎖狀態成功,表示獲取鎖成功,將當前線程設置爲佔有鎖的線程,即設置屬性exclusiveOwnerThread爲當前線程
setExclusiveOwnerThread(current);
//返回加鎖成功
return true;
}
}
//當前鎖已被佔有,判斷佔有鎖的線程是不是當前線程,若是不是直接返回獲取鎖失敗
else if (current == getExclusiveOwnerThread()) {
//鎖的原有狀態加上傳入進來要獲取的鎖數獲得新的鎖狀態值
int nextc = c + acquires;
//若是計算出的狀態值是負數,直接拋出Error錯誤,可是感受這裏會有些問題,好比原來的鎖狀態值爲1,傳入-1也會把鎖給釋放掉,這樣加鎖操做就變成了釋放鎖操做
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
//設置鎖的狀態值爲新的狀態值nextc
setState(nextc);
//返回獲取鎖成功
return true;
}
//返回獲取鎖失敗
return false;
}
//此方法在ReentrantLock的unLock方法中使用到,釋放鎖,修改鎖的狀態
//此方法只能在佔有鎖的線程調用,即unLock方法只能在持有鎖的線程進行鎖的釋放
//@param releases 要釋放的鎖數
protected final boolean tryRelease(int releases) {
//獲得鎖的新狀態值
int c = getState() - releases;
//若是當前線程不是持有鎖的線程,直接拋出IllegalMonitorStateException異常
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
//釋放鎖是否成功的標誌位
boolean free = false;
//若是新的鎖狀態值爲0
if (c == 0) {
//將釋放鎖是否成功的標誌位設置爲成功
free = true;
//將佔有獨佔鎖的線程,即屬性exclusiveOwnerThread置爲空
setExclusiveOwnerThread(null);
}
//設置鎖的狀態
setState(c);
//返回釋放鎖成功
return free;
}
//判斷當前線程是不是持有鎖的線程,若是是返回true,不然返回false
protected final boolean isHeldExclusively() {
//返回當前線程是不是持有鎖的線程
return getExclusiveOwnerThread() == Thread.currentThread();
}
//建立條件變量實例ConditionObject
final ConditionObject newCondition() {
//返回新建的ConditionObject實例
return new ConditionObject();
}
//獲取佔有鎖的線程
final Thread getOwner() {
//若是當前處於無鎖狀態,返回null,不然返回佔有鎖的線程
return getState() == 0 ? null : getExclusiveOwnerThread();
}
//獲得鎖的被獲取數,也是鎖的狀態,只能在持有鎖的線程操做才能獲取到鎖的狀態,即鎖的被獲取數,不然直接返回0
final int getHoldCount() {
//只能在持有鎖的線程操做才能獲取到鎖的狀態,即鎖的被獲取數,不然直接返回0
return isHeldExclusively() ? getState() : 0;
}
//判斷鎖是否有被線程佔有,即鎖的狀態是不是處於加鎖的狀態
final boolean isLocked() {
//鎖的狀態不等於0,代表鎖被線程佔有,鎖狀態處於加鎖狀態
return getState() != 0;
}
//從工做流中獲得鎖的對象,此方法目前沒有使用到
private void readObject(java.io.ObjectInputStream s) throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
//從新設置鎖的狀態
setState(0); // reset to unlocked state
}
}
複製代碼
//Sync的實現類,非公平的獲取鎖
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
//Sync的抽象lock方法的重寫,非公平的獲取鎖,在Reentrantlock的lock方法使用到
final void lock() {
//使用CAS將鎖的狀態從0更新成1,即加鎖操做
if (compareAndSetState(0, 1))
//若是加鎖成功,將當前線程設置爲佔有鎖的線程,即設置屬性exclusiveOwnerThread爲當前線程
setExclusiveOwnerThread(Thread.currentThread());
else
//NonfairSync從AQS中繼承下來的方法,下面在講鎖的獲取時會進行詳細的介紹
acquire(1);
}
//NonfairSync重寫了AbstractQueuedSynchronizer的tryAcquire模板方法,不然AQS中的tryAcquire方法會直接拋出UnsupportedOperationException異常
//tryAcquire方法在acquire中使用到,非公平的獲取鎖都是基於此方法
//@param acquires 要獲取的鎖數
protected final boolean tryAcquire(int acquires) {
//nonfairTryAcquire方法,在上面Sync內部中有進行介紹,非公平的獲取鎖,無需判斷同步隊列中前面是否有節點也在獲取鎖
return nonfairTryAcquire(acquires);
}
}複製代碼
//Sync的實現類,公平的獲取鎖
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
//Sync的抽象lock方法的重寫,公平的獲取鎖,在Reentrantlock的lock方法使用到
//FairSync的lock方法和NonfairSync的lock方法的區別是,NonfairSync的lock方法會嘗試先獲取鎖,若是鎖獲取不到纔會調用acquire方法,acquire內部也會嘗試再獲取鎖,若是獲取不到加入到同步隊列中循環獲取鎖
final void lock() {
//FairSync 從AQS中繼承下來的方法,下面在講鎖的獲取時會進行詳細的介紹
acquire(1);
}
//NonfairSync重寫了AbstractQueuedSynchronizer的tryAcquire模板方法,不然AQS中的tryAcquire方法會直接拋出UnsupportedOperationException異常
//tryAcquire方法在acquire中使用到,公平的獲取都是基於此方法
//tryAcquire方法和NonfairSync的tryAcquire方法不一樣的是須要調用hasQueuedPredecessors方法,判斷頭節點的下一個節點的線程是不是當前線程,若是不是代表前面有等待獲取鎖的線程
//@param acquires 要獲取的鎖數
protected final boolean tryAcquire(int acquires) {
//獲取當前要加鎖的線程
final Thread current = Thread.currentThread();
//獲取鎖的狀態,即AQS的屬性state值
int c = getState();
//若是鎖的狀態等於0,表示處於無鎖狀態
if (c == 0) {
//調用從AQS繼承下來的hasQueuedPredecessors方法判斷同步隊列是否有獲取鎖的節點的線程,若是是就不執行直接獲取鎖
if (!hasQueuedPredecessors() &&
//若是AQS同步隊列中沒有等待要獲取鎖的節點的線程,使用CAS更新鎖的狀態
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
//返回公平的獲取鎖成功
return true;
}
}
//若是當前線程是佔有鎖的線程
else if (current == getExclusiveOwnerThread()) {
//鎖的原有狀態加上傳入進來要獲取的鎖數獲得新的鎖狀態值
int nextc = c + acquires;
//若是計算出的狀態值是負數,直接拋出Error錯誤
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
//設置鎖的狀態值爲新的狀態值nextc
setState(nextc);
//返回公平的獲取鎖成功
return true;
}
//返回公平的獲取鎖失敗
return false;
}
}複製代碼
//Reentrantlock的lock方法,直到獲取獨佔鎖成功,在獲取鎖的過程當中,線程有可能須要阻塞進入等待狀態,不支持中斷
public void lock() {
//sync的抽象lock方法,由Sync的兩個子類FairSync和NonfairSync對lock進行重寫,因爲是非公平的獲取鎖,爲此調用的是下面介紹的NonfairSync的重寫的lock方法
sync.lock();
}
//NonfairSync重寫Sync的lock方法
final void lock() {
//因爲是非公平的獲取鎖,爲此先使用CAS將鎖的狀態從0變成1,即加鎖操做
if (compareAndSetState(0, 1))
//將表示佔有獨佔鎖的線程屬性exclusiveOwnerThread賦值爲當前線程
setExclusiveOwnerThread(Thread.currentThread());
else
//調用sync的acquire方法,acquire是AbstractQueuedSynchronizer類中的方法,由sync繼承下來
acquire(1);
}
//acquire由Sync從AbstractQueuedSynchronizer類中繼承下來的方法
public final void acquire(int arg) {
//tryAcquire方法是個模板方法,AQS中此方法直接拋出UnsupportedOperationException異常,NonfairSync有對AQS中的tryAcquire方法進行實現,NonfairSync的tryAcquire能夠看下面介紹
//在調用NonfairSync的tryAcquire方法嘗試獲取獨佔鎖,若是獲取獨佔鎖失敗纔會調用AQS中的acquireQueued方法循環進行獲取獨佔鎖,直到獲取獨佔鎖成功
if (!tryAcquire(arg) &&
//addWaiter方法先建立一個要獲取獨佔鎖的新節點,加入到同步隊列中,acquireQueued死循環的獲取獨佔鎖,直到獲取獨佔鎖成功
acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) //addWaiter、acquireQueued、selfInterrupt方法都是AQS中的方法
//重置線程的中斷標誌位,能夠看下面對selfInterrupt方法的介紹
selfInterrupt();
}
//NonfairSync重寫Sync從AQS繼承下來的tryAcquire方法
protected final boolean tryAcquire(int acquires) {
//調用Sync中nonfairTryAcquire方法,非公平的嘗試獲取鎖,下面進行介紹
return nonfairTryAcquire(acquires);
}
//Sync的nonfairTryAcquire方法,非公平的獲取鎖
final boolean nonfairTryAcquire(int acquires) {
//獲取當前要加鎖的線程
final Thread current = Thread.currentThread();
//獲取鎖的狀態,即AQS的屬性state值
int c = getState();
//若是鎖的狀態等於0,表示處於無鎖狀態
if (c == 0) {
//使用CAS更新鎖狀態,將鎖狀態更新成要獲取的鎖數
if (compareAndSetState(0, acquires)) {
//若是CAS更新鎖狀態成功,表示獲取鎖成功,將當前線程設置爲佔有鎖的線程,即設置屬性exclusiveOwnerThread爲當前線程
setExclusiveOwnerThread(current);
//返回加鎖成功
return true;
}
}
//當前鎖已被佔有,判斷佔有鎖的線程是不是當前線程,若是不是直接返回獲取鎖失敗
else if (current == getExclusiveOwnerThread()) {
//鎖的原有狀態加上傳入進來要獲取的鎖數獲得新的鎖狀態值
int nextc = c + acquires;
//若是計算出的狀態值是負數,直接拋出Error錯誤,可是感受這裏會有些問題,好比原來的鎖狀態值爲1,傳入-1也會把鎖給釋放掉,這樣加鎖操做就變成了釋放鎖操做
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
//設置鎖的狀態值爲新的狀態值nextc
setState(nextc);
//返回獲取鎖成功
return true;
}
//返回獲取鎖失敗
return false;
}
//Sync從AbstractQueuedSynchronizer繼承下來的addWaiter方法
//@param mode 要建立節點的模式,是要獲取獨佔鎖的節點仍是獲取共享鎖鎖的節點
private Node addWaiter(Node mode) {
//根據當前線程和傳入的節點模式建立新節點
Node node = new Node(Thread.currentThread(), mode);
//獲取AQS同步隊列(CLH)的尾節點
Node pred = tail;
//若是尾節點不爲空
if (pred != null) {
//將新建節點的前置節點設置爲尾節點
node.prev = pred;
//使用CAS將新建節點設置爲尾節點
if (compareAndSetTail(pred, node)) {
//若是CAS成功,尾節點的下一節點爲新建節點
pred.next = node;
//返回新建節點
return node;
}
}
//不然調用enq方法進行循環的將新建節點加入同步隊列中,作爲同步隊列的尾節點,詳細的能夠看enq方法的介紹
enq(node);
//返回新建節點
return node;
}
//Sync從AbstractQueuedSynchronizer繼承下來的enq方法,循環的將傳入節點加入同步隊列中,直到加入加入同步隊列爲此,作爲同步隊列的尾節點
private Node enq(final Node node) {
//死循環的將傳入節點加入到同步隊列中,作爲同步隊列的尾節點,直到節點加入隊列成功爲止
for (;;) {
//獲取尾節點
Node t = tail;
//若是尾節點爲空,代表同步隊列不存在節點
if (t == null) {
//新建個節點作爲同步隊列的頭節點,使用CAS進行頭節點的設置
if (compareAndSetHead(new Node()))
//若是頭節點設置成功,將尾節點設置爲頭節點
tail = head;
} else {//不然隊列不爲空
//將新建節點的前置節點設置爲尾節點
node.prev = t;
//使用CAS將新建節點設置爲尾節點
if (compareAndSetTail(t, node)) {
//若是CAS成功,尾節點的下一節點爲新建節點
t.next = node;
//返回新建節點
return t;
}
}
}
}
//Sync從AbstractQueuedSynchronizer中的acquireQueued方法,死循環的獲取獨佔鎖,直到獲取獨佔鎖成功爲此
//@param node 要獲取獨佔鎖的節點
//@param arg,要獲得獨佔鎖的獲取數,arg參數在NonfairSync中的tryAcquire方法使用到
//@return 在獲取獨佔鎖的過程當中,是否有發生中斷請求
final boolean acquireQueued(final Node node, int arg) {
//在獲取獨佔鎖是否失敗,若是失敗在finally中將節點從同步隊列中移除
boolean failed = true;
try {
//線程在獲取獨佔鎖阻塞的過程當中是否有其餘線程發起中斷請求,中斷請求的標誌位
boolean interrupted = false;
//死循環的獲取獨佔鎖,直到獲取獨佔鎖成功
for (;;) {
//獲取傳入節點的前置節點
final Node p = node.predecessor();
//傳入節點的前置節點若是爲頭節點,調用NonfairSync中的重寫AQS類中的tryAcquire(arg)方法
if (p == head && tryAcquire(arg)) {
//將傳入節點設置爲同步隊列的頭節點
setHead(node);
//傳入節點的前置節點的下一節點設置爲空
p.next = null; // help GC
//設置獲取獨佔鎖成功標誌位
failed = false;
//返回當前線程在獲取獨佔鎖的過程當中是否有發生中斷標誌位
return interrupted;
}
//shouldParkAfterFailedAcquire方法在上一次獲取獨佔鎖失敗時,是否須要阻塞,根據當前節點的前置節點狀態來判斷,詳細的能夠看下面的介紹
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt()) //parkAndCheckInterrupt方法阻塞當前線程,而且在當前線程被喚醒時,檢查當前線程是否被中斷,parkAndCheckInterrupt返回中斷標誌位,詳細的能夠看下面的介紹
//parkAndCheckInterrupt返回線程在阻塞被喚醒時,線程是否被中斷的標誌位
interrupted = true;
}
} finally {
//若是獲取獨佔鎖失敗
if (failed)
//若是獲取獨佔鎖失敗,從同步隊列中移除當前節點,根據當前節點的前置節點狀態是否喚醒當前節點的不爲空的下一節點線程,cancelAcquire方法能夠看下面詳細介紹
cancelAcquire(node);
}
}
//AbstractQueuedSynchronizer中的selfInterrupt方法
static void selfInterrupt() {
//設置當前線程的中斷標誌位
Thread.currentThread().interrupt();
}
//Sync從AbstractQueuedSynchronizer繼承下來的shouldParkAfterFailedAcquire方法
//即線程在上一次沒有獲取到獨佔鎖,再次獲取獨佔鎖時是否須要阻塞
//@param pred 傳入節點node的前置節點
//@param node 要獲取獨佔鎖的節點
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
//獲取前置節點的狀態,若是對AQS狀態不清楚的能夠看下另外一篇AQS源碼分析
int ws = pred.waitStatus;
//若是前置節點的狀態爲Node.SIGNAL,SIGNAL狀態表示下一節點須要阻塞
if (ws == Node.SIGNAL)
//返回當前要獲取獨佔鎖的節點須要阻塞
return true;
//若是當前要獲取獨佔鎖的節點的前置節點已取消CANCELLED,從新獲取有效的前置節點
if (ws > 0) {
do {
//從新設置要獲取獨佔鎖節點的前置節點
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);//循環獲取前面有效的前置節點,CLH隊列必定會有個有效的頭節點
//有效的前置節點的下一節點設置爲當前要獲取獨佔鎖的節點
pred.next = node;
} else {
//不然將前置節點的狀態設置爲Node.SIGNAL,在下一次循環時,將其要獲取獨佔鎖的節點阻塞
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
//返回不須要阻塞要獲取獨佔鎖的節點的線程
return false;
}
//Sync從AbstractQueuedSynchronizer繼承下來的parkAndCheckInterrupt方法
private final boolean parkAndCheckInterrupt() {
//阻塞當前線程,this是監控對象,這樣能夠知道當前線程是被那個對象阻塞
LockSupport.park(this);
//線程被喚醒時,判斷在等待的過程當中是否有中斷請求
return Thread.interrupted();
}
//Sync從AbstractQueuedSynchronizer中的cancelAcquire方法
//將傳入節點從同步隊列中移除,若是要移除節點爲尾節點,從新設置尾節點,若是要移除節點的前置節點爲頭節點,喚醒要取消節點的下一節點
//@param node 要取消的節點
private void cancelAcquire(Node node) {
//若是傳入的要取消節點爲空,直接退出
if (node == null)
//直接退出
return;
//將要取消節點的線程置爲空
node.thread = null;
//獲取要取消節點的前置節點
Node pred = node.prev;
//循環獲取不是取消的前置節點節點
while (pred.waitStatus > 0)
node.prev = pred = pred.prev;
//獲取前置節點的下一個節點,在下面cas須要使用到
Node predNext = pred.next;
//將要取消節點的狀態設置爲取消Node.CANCELLED狀態
node.waitStatus = Node.CANCELLED;
//若是要取消節點爲尾節點,將其尾節點設置爲有效的前置節點
if (node == tail && compareAndSetTail(node, pred)) {
//將有效的前置節點的下一節點設置爲空
compareAndSetNext(pred, predNext, null);
} else {
//不然的話根據有效的前置節點狀態和是否頭節點來判斷是否須要喚醒要取消節點的下一節點
int ws;
//有效的前置節點不是頭節點
if (pred != head &&
//有效的前置節點狀態爲Node.SIGNAL,或者使用cas將有效的前置節點的狀態設置爲Node.SIGNAL,而且有效的前置節點的線程不爲空
((ws = pred.waitStatus) == Node.SIGNAL ||
(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
pred.thread != null) {
//獲取要取消節點的下一個節點
Node next = node.next;
//要取消節點的下一個節點不爲空,而且不是已取消狀態
if (next != null && next.waitStatus <= 0)
//將要取消節點的下一個節點和有效的前置節點鏈接起來
compareAndSetNext(pred, predNext, next);
} else {
//喚醒要取消節點的下一個節點unparkSuccessor方法能夠看下面
unparkSuccessor(node);
}
//將要取消節點的下一個節點設置爲自身
node.next = node; // help GC
}
}
//Sync從AbstractQueuedSynchronizer中的unparkSuccessor方法
//喚醒當前傳入節點的下一個不爲空而且不是取消的節點線程
//@param node 喚醒傳入節點下一節點
private void unparkSuccessor(Node node) {
//傳入節點的狀態
int ws = node.waitStatus;
//若是傳入節點的狀態小於0,即SIGNAL或者PROPAGATE
if (ws < 0)
//使用CAS將傳入節點的狀態設置爲0
compareAndSetWaitStatus(node, ws, 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;
}
//若是下一個有效節點不爲空,而且不是已取消狀態,喚醒此節點對應的線程
if (s != null)
//喚醒下一節點的線程
LockSupport.unpark(s.thread);
}
//Reentrantlock的lockInterruptibly方法,直到獲取獨佔鎖成功或者在獲取鎖的過程當中,線程有可能須要阻塞進入等待狀態,在等待被喚醒時,若是線程被中斷,直接拋出中斷異常,支持中斷
//和Reentrantlock的lock方法的差異,在獲取獨佔鎖阻塞等待被喚醒時,線程被中斷,拋出中斷異常
public void lockInterruptibly() throws InterruptedException {
//調用sync從AQS中繼承下來的acquireInterruptibly方法,能夠看下面對此方法的介紹
sync.acquireInterruptibly(1);
}
//Sync從AbstractQueuedSynchronizer繼承下來的acquireInterruptibly方法
//@param arg 要獲取獨佔鎖的獲取數
public final void acquireInterruptibly(int arg) throws InterruptedException {
//要獲取獨佔鎖的線程被中斷,拋出中斷異常
if (Thread.interrupted())
throw new InterruptedException();
//tryAcquire方法是個模板方法,AQS中此方法直接拋出UnsupportedOperationException異常,NonfairSync有對AQS中的tryAcquire方法進行實現,NonfairSync的tryAcquire能夠看下面介紹
//在調用NonfairSync的tryAcquire方法嘗試獲取獨佔鎖,若是獲取獨佔鎖失敗纔會調用AQS中的doAcquireInterruptibly方法循環進行獲取獨佔鎖,直到獲取獨佔鎖成功或者線程被中斷拋出中斷異常
if (!tryAcquire(arg))
//若是調用tryAcquire方法失敗,調用sync從AQS中繼承下來的doAcquireInterruptibly方法,能夠看下面對此方法的介紹
doAcquireInterruptibly(arg);
}
//Sync從AbstractQueuedSynchronizer繼承下來的doAcquireInterruptibly方法,和上面介紹的acquireQueued方法惟一不一樣是,在線程Wait被喚醒時,檢測線程是否被中斷,若是被中斷直接拋出中斷異常
private void doAcquireInterruptibly(int arg) throws InterruptedException {
//根據當前線程和獨佔模式建立新節點,addWaiter方法能夠看上面的介紹
final Node node = addWaiter(Node.EXCLUSIVE);
//在獲取獨佔鎖是否失敗,若是失敗在finally中將節點從同步隊列中移除
boolean failed = true;
try {
//死循環的獲取獨佔鎖,直到獲取獨佔鎖成功或者拋出中斷異常
for (;;) {
//獲取新建節點的前置節點
final Node p = node.predecessor();
//新建節點的前置節點若是爲頭節點,調用NonfairSync中重寫AQS類中的tryAcquire(arg)方法
if (p == head && tryAcquire(arg)) {
//將新建節點設置爲同步隊列的頭節點
setHead(node);
//新建節點的前置節點的下一節點設置爲空
p.next = null; // help GC
//設置獲取獨佔鎖成功標誌位
failed = false;
//直接退出
return;
}
//shouldParkAfterFailedAcquire方法在上一次獲取獨佔鎖失敗時,是否須要阻塞,根據當前節點的前置節點狀態來判斷,詳細的能夠看上面的介紹
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt()) //parkAndCheckInterrupt方法阻塞當前線程,而且在當前線程被喚醒時,檢查當前線程是否被中斷,parkAndCheckInterrupt返回中斷標誌位,詳細的能夠看上面的介紹
//parkAndCheckInterrupt返回線程在等待被喚醒時,線程是否被中斷的標誌位,線程被中斷拋出中斷異常
throw new InterruptedException();
}
} finally {
//若是獲取獨佔鎖失敗
if (failed)
//若是獲取獨佔鎖失敗,從同步隊列中移除當前節點,根據當前節點的前置節點狀態是否喚醒當前節點的不爲空的下一節點線程,cancelAcquire方法能夠看上面詳細介紹
cancelAcquire(node);
}
}
//Reentrantlock的tryLock方法,嘗試獲取獨佔鎖,獲取不到直接返回,不會加入同步隊列中,不支持中斷
public boolean tryLock() {
////調用在Sync介紹的nonfairTryAcquire方法
return sync.nonfairTryAcquire(1);
}
//Reentrantlock的tryLock(long timeout, TimeUnit unit)方法,超時的獲取獨佔鎖,支持中斷,若是線程在獲取獨佔鎖的過程當中,被中斷,拋出中斷異常
//和Reentrantlock的lock方法的區別是支持超時的獲取鎖,獲取不到直接返回獲取獨佔鎖失敗,lock要獲取到獨佔鎖纔會退出,lock方法不會拋出中斷異常
public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
//調用sync從AQS中繼承下來的tryAcquireNanos方法,能夠看下面對此方法的介紹
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
//Sync從AbstractQueuedSynchronizer繼承下來的tryAcquireNanos方法
//@param arg 要獲取獨佔鎖的獲取數
public final boolean tryAcquireNanos(int arg, long nanosTimeout) throws InterruptedException {
//要獲取獨佔鎖的線程被中斷,拋出中斷異常
if (Thread.interrupted())
//拋出中斷異常
throw new InterruptedException();
//tryAcquire方法是個模板方法,AQS中此方法直接拋出UnsupportedOperationException異常,NonfairSync有對AQS中的tryAcquire方法進行實現,NonfairSync的tryAcquire能夠看下面介紹
//在調用NonfairSync的tryAcquire方法嘗試獲取獨佔鎖,若是獲取獨佔鎖失敗纔會調用AQS中的doAcquireNanos方法循環進行獲取獨佔鎖,直到獲取獨佔鎖成功或者超時退出或者線程被中斷拋出中斷異常
return tryAcquire(arg) ||
//若是調用tryAcquire方法失敗,調用sync從AQS中繼承下來的doAcquireInterruptibly方法,能夠看下面對此方法的介紹
doAcquireNanos(arg, nanosTimeout);
}
//@param arg 要獲取獨佔鎖的獲取數
//@param nanosTimeout 獲取獨佔鎖的超時時間,若是超時返回獲取獨佔鎖失敗
//@thorws InterruptedException 線程在獲取獨佔鎖的線程被中斷,拋出中斷異常
private boolean doAcquireNanos(int arg, long nanosTimeout) throws InterruptedException {
//若是超時時間小於等於0,直接返回獲取獨佔鎖失敗
if (nanosTimeout <= 0L)
//返回獲取獨佔鎖失敗
return false;
//當前時間加上超時時間,獲得獲取獨佔鎖線程的死亡時間
final long deadline = System.nanoTime() + nanosTimeout;
//根據當前線程和獨佔模式建立新節點,addWaiter方法能夠看上面的介紹
final Node node = addWaiter(Node.EXCLUSIVE);
//在獲取獨佔鎖是否失敗,若是失敗在finally中將節點從同步隊列中移除
boolean failed = true;
try {
//死循環的獲取獨佔鎖,直到獲取獨佔鎖成功或者拋出中斷異常
for (;;) {
//獲取新建節點的前置節點
final Node p = node.predecessor();
//新建節點的前置節點若是爲頭節點,調用NonfairSync中重寫AQS類中的tryAcquire(arg)方法
if (p == head && tryAcquire(arg)) {
//將新建節點設置爲同步隊列的頭節點
setHead(node);
//新建節點的前置節點的下一節點設置爲空
p.next = null; // help GC
//設置獲取獨佔鎖成功標誌位
failed = false;
//返回獲取獨佔鎖成功
return true;
}
//死亡時間減去當前時間,獲得新的超時時間
nanosTimeout = deadline - System.nanoTime();
//若是新的超時時間小於等於0,直接返回獲取獨佔鎖失敗
if (nanosTimeout <= 0L)
//返回獲取獨佔鎖失敗
return false;
//shouldParkAfterFailedAcquire方法在上一次獲取獨佔鎖失敗時,是否須要阻塞,根據當前節點的前置節點狀態來判斷,詳細的能夠看上面的介紹
if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > spinForTimeoutThreshold) //超時時間須要大於AQS屬性spinForTimeoutThreshold值,纔會阻塞線程,不然讓其線程自旋一段時間獲取獨佔鎖
//模擬讓線程等待必定時間,unpark喚醒或者超時自動喚醒
LockSupport.parkNanos(this, nanosTimeout);
//判斷當前獲取獨佔鎖的線程是否被中斷
if (Thread.interrupted())
//若是被中斷拋出中斷異常
throw new InterruptedException();
}
} finally {
//若是獲取獨佔鎖失敗
if (failed)
//若是獲取獨佔鎖失敗,從同步隊列中移除當前節點,根據當前節點的前置節點狀態是否喚醒當前節點的不爲空的下一節點線程,cancelAcquire方法能夠看上面詳細介紹
cancelAcquire(node);
}
}
複製代碼
//Reentrantlock的lock方法,sync屬性爲FairSync
public void lock() {
//sync的抽象lock方法,由Sync的兩個子類FairSync和NonfairSync對lock進行重寫,因爲是公平的獲取獨佔鎖,爲此調用的是下面介紹的FairSync的重寫的lock方法
sync.lock();
}
//FairSync重寫Sync的lock方法,與NonfairSync重寫Sync的lock方法不同的是,直接調用acquire方法進行獲取獨佔鎖,NonfairSync的lock方法首先會使用cas嘗試加鎖
final void lock() {
//調用sync的acquire方法,acquire是AbstractQueuedSynchronizer類中的方法,由sync繼承下來,看下面對此方法的介紹
acquire(1);
}
//acquire由Sync從AbstractQueuedSynchronizer類中繼承下來的方法
public final void acquire(int arg) {
//tryAcquire方法是個模板方法,AQS中此方法直接拋出UnsupportedOperationException異常,FairSync有對AQS中的tryAcquire方法進行實現,FairSync的tryAcquire能夠看下面介紹
//在調用FairSync的tryAcquire方法嘗試獲取獨佔鎖,若是獲取獨佔鎖失敗纔會調用AQS中的acquireQueued方法循環進行獲取獨佔鎖,直到獲取獨佔鎖成功
if (!tryAcquire(arg) &&
//addWaiter方法先建立一個要獲取獨佔鎖的新節點,加入到同步隊列中,acquireQueued死循環的獲取獨佔鎖,直到獲取獨佔鎖成功
acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) //addWaiter、acquireQueued、selfInterrupt方法都是AQS中的方法,在上面非公平的獲取獨佔鎖有對這些方法進行介紹
//重置線程的中斷標誌位,在非公平的獲取獨佔鎖有對selfInterrupt方法進行介紹,詳細的能夠看上面
selfInterrupt();
}
//FairSync重寫Sync從AQS繼承下來的tryAcquire方法
protected final boolean tryAcquire(int acquires) {
//獲取當前要加鎖的線程
final Thread current = Thread.currentThread();
//獲取鎖的狀態,即AQS的屬性state值
int c = getState();
//若是鎖的狀態等於0,表示處於無鎖狀態
if (c == 0) {
//調用從AQS繼承下來的hasQueuedPredecessors方法判斷同步隊列是否有獲取鎖的節點的線程,若是是就不執行直接獲取鎖
if (!hasQueuedPredecessors() &&
//若是AQS同步隊列中沒有等待要獲取鎖的節點的線程,使用CAS更新鎖的狀態
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
//返回公平的獲取鎖成功
return true;
}
}
//若是當前線程是佔有鎖的線程
else if (current == getExclusiveOwnerThread()) {
//鎖的原有狀態加上傳入進來要獲取的鎖數獲得新的鎖狀態值
int nextc = c + acquires;
//若是計算出的狀態值是負數,直接拋出Error錯誤
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
//設置鎖的狀態值爲新的狀態值nextc
setState(nextc);
//返回公平的獲取鎖成功
return true;
}
//返回公平的獲取鎖失敗
return false;
}
//sync從AbstractQueuedSynchronizer類中繼承下來的hasQueuedPredecessors方法
public final boolean hasQueuedPredecessors() {
//獲取AQS中的同步隊列尾節點
Node t = tail;
//獲取AQS中的同步隊列頭節點
Node h = head;
Node s;
//若是同步隊列的頭尾節點不相等,而且頭節點的下一節點等於空,代表同步隊列中存在要獲取獨佔鎖的節點,或者同步隊列的頭節點的下一節點中的線程不是當前線程,返回true,須要阻塞
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
//Reentrantlock的lockInterruptibly方法,直到獲取獨佔鎖成功或者在獲取鎖的過程當中,線程有可能須要阻塞進入等待狀態,在等待被喚醒時,若是線程被中斷,直接拋出中斷異常,支持中斷
//和Reentrantlock的lock方法的差異,在獲取獨佔鎖阻塞等待被喚醒時,線程被中斷,拋出中斷異常
public void lockInterruptibly() throws InterruptedException {
//調用sync從AQS中繼承下來的acquireInterruptibly方法,acquireInterruptibly在上面非公平的獲取獨佔鎖有對其進行介紹,只是內部調用tryAcquire是FairSync重寫的tryAcquire方法,其餘都同樣,不清楚的能夠看上面
sync.acquireInterruptibly(1);
}
//Reentrantlock的tryLock方法,嘗試獲取獨佔鎖,獲取不到直接返回,不會加入同步隊列中,不支持中斷
public boolean tryLock() {
//調用在Sync介紹的nonfairTryAcquire方法
return sync.nonfairTryAcquire(1);
}
//Reentrantlock的tryLock(long timeout, TimeUnit unit)方法,超時的獲取獨佔鎖,支持中斷,若是線程在獲取獨佔鎖的過程當中,被中斷,拋出中斷異常
//和Reentrantlock的lock方法的區別是支持超時的獲取鎖,獲取不到直接返回獲取獨佔鎖失敗,lock要獲取到獨佔鎖纔會退出,lock方法不會拋出中斷異常
public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
//調用sync從AQS中繼承下來的tryAcquireNanos方法,tryAcquireNanos在上面非公平的獲取獨佔鎖有對其進行介紹,只是內部調用tryAcquire是FairSync重寫的tryAcquire方法,其餘都同樣,不清楚的能夠看上面
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
複製代碼
//Reentrantlock的unlock方法,釋放獨佔鎖
public void unlock() {
//調用Sync從AQS中繼承下來的release方法,詳細的能夠看下面的介紹
sync.release(1);
}
//sync從AbstractQueuedSynchronizer類中繼承下來的release
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
//若是頭節點不爲空,而且狀態不是0,狀態是0的話,後面的節點都不會阻塞爲此不用喚醒
if (h != null && h.waitStatus != 0)
//Sync從AbstractQueuedSynchronizer中的unparkSuccessor方法
//喚醒當前傳入節點的下一個不爲空而且不是取消的節點線程
unparkSuccessor(h);
//返回釋放獨佔鎖成功
return true;
}
//返回釋放獨佔鎖失敗
return false;
}
//sync的tryRelease方法
//此方法只能在佔有鎖的線程調用,即unLock方法只能在持有鎖的線程進行鎖的釋放
//@param releases 要釋放的鎖數
protected final boolean tryRelease(int releases) {
//獲得鎖的新狀態值
int c = getState() - releases;
//若是當前線程不是持有鎖的線程,直接拋出IllegalMonitorStateException異常
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
//釋放鎖是否成功的標誌位
boolean free = false;
//若是新的鎖狀態值爲0
if (c == 0) {
//將釋放鎖是否成功的標誌位設置爲成功
free = true;
//將佔有獨佔鎖的線程,即屬性exclusiveOwnerThread置爲空
setExclusiveOwnerThread(null);
}
//設置鎖的狀態
setState(c);
//返回釋放鎖成功
return free;
}複製代碼