上一篇分享了AQS的基本原理:AQS(AbstractQueuedSynchronizer),在此基礎上,再來看看ReentrantLock對AQS是怎麼實現的,尤爲是對可重入以及公平和非公平的理解java
先看看lock()方法:ui
final void lock() { acquire(1); }
/** *對AQS中對應方法的重寫,位於FairSync類中,鎖公平獲取實現方式 */ protected final boolean tryAcquire(int acquires) {//acquires=1 final Thread current = Thread.currentThread();//獲取當前線程 int c = getState();//獲取AQS中state的值,0表示資源未被佔用,既沒有線程獲取到鎖 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; }
大概流程:線程
主要再來看一下hasQueuedPredecessors():code
/** *判斷隊列裏面有沒有比當前線程等待更久更先到等待隊列的線程,越靠近head越優先獲取鎖即先到先得(公平性) */ public final boolean hasQueuedPredecessors() { Node t = tail; Node h = head;//當前已經得到鎖的線程節點 Node s; return h != t && ((s = h.next) == null || s.thread != Thread.currentThread()); }
先來看看lock()方法:htm
final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); }
和公平方式不一樣的是,他會先嚐試把state設置成1,若是設置成功,那就把持有鎖的線程設置爲本身,不然纔去正常獲取鎖。
再看他對tryAcquire的重寫:blog
protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); }
/** *非公平方式獲取鎖 */ final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { //該步驟相似於上面lock()方法的第一步 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; }
public void unlock() { sync.release(1); }
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; }