AQS 使用一個(gè) volatile 的 int 類型的成員變量來表示同步狀態(tài),通過內(nèi)置的 FIFO 隊(duì)列來完成資源獲取和排隊(duì)工作,將每條要去搶占資源的線程封裝成一個(gè) node 節(jié)點(diǎn)來實(shí)現(xiàn)鎖的分配,通過 CAS 來完成對(duì) state 值的修改。
HashMap 進(jìn)行 put 的時(shí)候,也不是直接存儲(chǔ) key value 鍵值對(duì),而是將 key value 鍵值對(duì)封裝成 Node 節(jié)點(diǎn),然后用數(shù)組 + 鏈表 + 紅黑樹存儲(chǔ) Node。AQS 也類似,將要搶占資源的 Thread 封裝成 Node節(jié)點(diǎn)。
二. 相關(guān)源碼:
public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable {
static final class Node { …… volatile int waitStatus; volatile Node prev; volatile Node next; volatile Thread thread; …… }
/** * Creates an instance of {@code ReentrantLock}. * This is equivalent to using {@code ReentrantLock(false)}. */ public ReentrantLock() { sync = new NonfairSync(); }
通過這個(gè)構(gòu)造方法可以知道,實(shí)際上是構(gòu)建了一個(gè)非公平鎖。如果 new 的時(shí)候傳了 true,調(diào)用的構(gòu)造方法就是:
/** * 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(); }
所以傳的是 true,構(gòu)建的就是公平鎖。
2. 公平和非公平有什么區(qū)別?
非公平鎖源碼:
final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); returntrue; } } elseif (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) // overflow throw new Error("Maximum lock count exceeded"); setState(nextc); returntrue; } returnfalse; }
公平鎖源碼:
protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { if (!hasQueuedPredecessors() && compareAndSetState(0, acquires)) { setExclusiveOwnerThread(current); returntrue; } } elseif (current == getExclusiveOwnerThread()) { int nextc = c + acquires; if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); returntrue; } returnfalse; }
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()); }