ReentrantLock 重入鎖是對 synchronized 的一種補充,ReentrantLock 提供了可定時、可輪詢的與可中斷的鎖獲取操做,公平隊列,以及非塊結構的鎖。與 synchronized 相比, ReentrantLock 更加靈活可控,伸縮性更好。ReentrantLock 的非公平鎖性能也比 synchronized 更好。
經過對 CAS 的瞭解,咱們知道 CAS 底層也是經過排它鎖實現的,只不過 CAS 是 CPU 觸發的,效率更高。ReentrantLock 實現方式和 AtomicInteger 方式相似,不過 ReentrantLock 藉助 AbstractQueuedSynchronizer 類來實現獨佔鎖的功能。
ReentrantLock 主要方法以下:java
ReentrantLock 結構:node
public class ReentrantLock implements Lock, Serializable { private static final long serialVersionUID = 7373984872572414699L; private final ReentrantLock.Sync sync; public ReentrantLock() { this.sync = new ReentrantLock.NonfairSync(); } public ReentrantLock(boolean var1) { this.sync = (ReentrantLock.Sync)(var1?new ReentrantLock.FairSync():new ReentrantLock.NonfairSync()); } public void lock() { this.sync.lock(); } public void lockInterruptibly() throws InterruptedException { sync.acquireInterruptibly(1); } public boolean tryLock() { return sync.nonfairTryAcquire(1); } public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException { return sync.tryAcquireNanos(1, unit.toNanos(timeout)); } public void unlock() { sync.release(1); } }
ReentrantLock 獲取鎖能夠經過 lock 和 tryLock 獲取,lock 方法獲取時,若是所沒被佔用直接獲取,若是被本線程佔用,則直接獲取,不然加入等待隊列,並阻塞線程;tryLock 方法獲取時,若是所沒被佔用直接獲取,若是被本線程佔用,也直接獲取,若是被其餘線程佔用,則馬上返回失敗。
從 ReentrantLock 中咱們能夠看到 ReentrantLock 的鎖是經過 Sync 這個類完成的,Sync 則繼承自 AbstractQueuedSynchronizer,AQS 是獨佔鎖和共享鎖的父類,經過 AQS 的 compareAndSetState 方法來進行加鎖從而實現獨佔鎖的功能。
Sync 有兩個子類,分別是 FairSync 和 NonfairSync。
NonfairSync 結構:less
/** * 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() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); } }
NonfairSync 則先嚐試獲取鎖,若是獲取失敗則再加入等待隊列。ReentrantLock 默認是非公平鎖。
FairSync 結構:函數
/** * Sync object for fair locks */ static final class FairSync extends Sync { private static final long serialVersionUID = -3000897897090466540L; final void lock() { acquire(1); } /** * 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) { 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; } }
FairSync 判斷是否有線程等待,若是沒有則嘗試獲取鎖,若是有則加入到等待隊列。
AQS 結構:性能
public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements Serializable { private static final long serialVersionUID = 7373984972572414691L; private transient volatile AbstractQueuedSynchronizer.Node head; private transient volatile AbstractQueuedSynchronizer.Node tail; private volatile int state; static final long spinForTimeoutThreshold = 1000L; private static final Unsafe unsafe = Unsafe.getUnsafe(); private static final long stateOffset; private static final long headOffset; private static final long tailOffset; private static final long waitStatusOffset; private static final long nextOffset; protected AbstractQueuedSynchronizer() { } protected final boolean compareAndSetState(int var1, int var2) { return unsafe.compareAndSwapInt(this, stateOffset, var1, var2); } public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); } final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { boolean interrupted = false; for (;;) { final Node p = node.predecessor(); if (p == head && tryAcquire(arg)) { setHead(node); p.next = null; // help GC failed = false; return interrupted; } if (shouldParkAfterFailedAcquire(p, node) && parkAndCheckInterrupt()) interrupted = true; } } finally { if (failed) cancelAcquire(node); } } public final boolean release(int arg) { if (tryRelease(arg)) { Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h); return true; } return false; } }
ReentrantLock 是經過使用 AQS 類來實現的,ReentrantLock 調用 lock 方法時,調用 AQS 的 acquire 方法,acquire 方法則調用子類 tryAcquire 方法,子類 tryAcquire 方法則分別有個 NonFairSync 和 FairSync 實現,若是獲取失敗則加入到等待隊列中去。ReentrantLock 調用 unlock 方法時,調用 AQS 的 release 方法,release 方法則調用子類 tryRelease 方法,子類 release 成功後,則喚醒等待隊列的第一個線程。ui