AbstractQueuedSynchronizer (AQS)類如其名,抽象的隊列式同步容器,AQS定義類一套多線程訪問共享資源的同步器,許多同步類的實現都依賴於它,好比以前學習的ReentrantLock/Semaphore/CountDownLatch。java
AQS阻塞隊列.png
1。自定義同步器在實現時只須要實現共享資源state的獲取於釋放方式便可,至於具體線程等待隊列的維護(如獲取資源失敗入隊/喚醒出隊等),AQS已經在頂層實現好了,自定義同步容器實現時主要實現如下幾種方法:
2.isHeldExclusively():該線程是否正在獨佔資源,只有用到condition才須要取實現它。
3.tryAcquire(int):獨佔方式,嘗試獲取資源,成功則返回true,失敗則返回false。
4.tryRelease(int):獨佔方式,嘗試釋放資源,成功則返回true,失敗則返回false。
5.tryAcquireShared(int):共享方式,嘗試獲取資源,附屬表示獲取失敗,0表示獲取成功,可是沒有剩餘資源可用,其餘線程不能在獲取,正數表示獲取成功,而且有剩餘資源,也就是本身能夠重複獲取(可重入)。
6.tryReleaseShare(int):共享方式。嘗試釋放資源,成功返回true,失敗返回false。
7.以ReentrantLock爲例,state初始化爲0,表示未鎖定狀態。A線程lock()的時候,會調用tryAcquire()獨佔該鎖並將state+1。此後其餘線程在tryAcquire()獨佔該鎖並將state+1。此後表示其餘線程再tryAcquire()時就會失敗,直到A線程unlock()到state=0(幾鎖釋放)爲止,其餘線程纔有機會獲取該鎖。固然,釋放鎖以前,A線程本身是能夠重複獲取此鎖的(state會累加),這就是可重入的概念。但要注意,獲取多少次就要釋放多麼次,這樣才能保證state是能回到零態的。node
2.1 Reentrantlock類結構算法
public class ReentrantLock implements Lock, java.io.Serializable
能夠看出Reentrantlock 實現類lock接口,首先看下這個lock接口。多線程
public interface Lock { //普通的獲取鎖的方法,lock會阻塞直到成功 void lock(); //與lock不一樣的時,它能夠相應中斷, void lockInterruptibly() throws InterruptedException; //嘗試獲取鎖,當即返回,不阻塞,成功返回true,失敗返回false boolean tryLock(); //先嚐試獲取鎖,若是成功則返回true,失敗則阻塞等待,等待時間由參數決定,在等待的同時相應中斷,拋出中斷異常,若是在等待的過程當中得到類鎖則返回true,不然直到時間超時,則返回false。 boolean tryLock(long time, TimeUnit unit) throws InterruptedException; //普通釋放鎖的方法 void unlock(); //新建一個條件,lock能夠關聯多個條件,關於條件在之後篇幅中記錄 Condition newCondition(); }
能夠看出,顯示鎖,與synchronied相比,支持非阻塞的方式獲取鎖,能夠響應中斷,能夠限時,這使得它很是的靈活。
如今回到Reentrantlock類,能夠看到其內部基本上定義類三個內部類:less
public class ReentrantLock implements Lock, java.io.Serializable { private final Sync sync; ..... abstract static class Sync extends AbstractQueuedSynchronizer { ... } static final class NonfairSync extends Sync { .... } .... static final class FairSync extends Sync { ..... } ..... }
很顯然從上面的類結構,咱們能夠得出jdk利用CAS算法和AQS實現類ReentrantLock。ide
2.2. 構造函數分析函數
/** * Creates an instance of {@code ReentrantLock}. * This is equivalent to using {@code ReentrantLock(false)}. */ public ReentrantLock() { sync = new NonfairSync(); } /** * Creates an instance of {@code ReentrantLock} with the * given fairness policy. * * @param fair {@code true} if this lock should use a fair ordering policy */ public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); }
ReentrantLock出於性能考慮,默認採用非公平鎖。
2.3. 獲取鎖
2.3.1. 非公平模式下的加鎖性能
/** * 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算法,經過改變共享資源-state值,成功則設置當前線程爲持有鎖的線程(獨佔),失敗則調用頂層AQS的acquire方法,再次嘗試,失敗則將線程放到阻塞隊列 if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } ... }
2.3.2. 公平模式下的加鎖學習
/** * Sync object for fair locks */ static final class FairSync extends Sync { private static final long serialVersionUID = -3000897897090466540L; //獲取鎖 final void lock() { acquire(1); //在這裏調用的時AQS頂層方法,獲取失敗則將線程放到阻塞隊列末尾 } /** * 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) { //沒有其餘線程正在競爭當前的臨界資源,而且經過CAS加鎖成功,則設置當前的線程爲獨佔此資源的線程 if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); return true; } } //若是此時臨界資源已經被鎖定,則先判斷持有者是否時當前線程 else if (current == getExclusiveOwnerThread()) { //若是是持有者,則可重複獲取鎖,同時更新狀態值,注意加幾回鎖就要釋放幾回,直到爲0 int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; } }
2.3.三、acquireInterruptibly解析ui
public void lockInterruptibly() throws InterruptedException { //調用AQS頂層方法 sync.acquireInterruptibly(1); } //AQS頂層方法 public final void acquireInterruptibly(int arg) throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); if (!tryAcquire(arg)) doAcquireInterruptibly(arg); } //中斷響應 private void doAcquireInterruptibly(int arg) throws InterruptedException { final Node node = addWaiter(Node.EXCLUSIVE); boolean failed = true; try { for (;;) { final Node p = node.predecessor(); if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC failed = false; return; } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) throw new InterruptedException(); } } finally { if (failed) cancelAcquire(node); } } 大體過程以下: (1)若是線程已經中斷則直接拋出異常 (2)若是線程還沒中斷,則經過自旋方式,申請鎖直至到當前線程得到鎖,或失敗,而後響應中斷。
2.4 釋放鎖
protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) { free = true; setExclusiveOwnerThread(null); } setState(c); return free; }
其釋放獨佔鎖的過程大體以下:(1)先獲取當前資源狀態,減去釋放release,通常是1;(2)判斷當前線程是否鎖定資源的線程,若是不是則拋出異常;(3)假如資源狀態值爲0,則說明鎖已經釋放,將獨佔線程至空,更新狀態值,返回設置成功或失敗