AQS是Java併發包中很重要的一個抽象類,咱們所使用的ReentrantLock、ReentrantReadWriteLock、CountDownLatch、Semaphore等都是基於AQS來實現的。安全
AQS中維護了一個state變量這個表示共享的資源,以及一個CHL隊列(多線程爭奪資源的時候被阻塞的線程將會被放進這個隊列)。這個隊列不須要咱們去維護,咱們須要關注的幾個點就是state變量的獲取和釋放規則。
state 變量被聲明的類型是volatile類型保證多線程下的資源可見性,state=1表示當前資源被佔用。
state值的更新是經過CAS操做來保證它修改的安全性。
多線程
AQS中提供瞭如下主要的方法:併發
這裏對應獨佔鎖還有兩個方法是對應共享鎖的 tryShare方法。性能
private volatile int state;//共享變量,使用volatile修飾保證線程可見性 //返回同步狀態的當前值 protected final int getState() { return state; } // 設置同步狀態的值 protected final void setState(int newState) { state = newState; } //原子地(CAS操做)將同步狀態值設置爲給定值update若是當前同步狀態的值等於expect(指望值) protected final boolean compareAndSetState(int expect, int update) { return unsafe.compareAndSwapInt(this, stateOffset, expect, update); }
ReentrantLock 默認採用非公平鎖,由於考慮得到更好的性能,經過 boolean 來決定是否用公平鎖(傳入 true 用公平鎖)。ui
/** Synchronizer providing all implementation mechanics */ private final Sync sync; public ReentrantLock() { // 默認非公平鎖 sync = new NonfairSync(); } public ReentrantLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); }
ReentrantLock 中公平鎖的 lock 方法this
static final class FairSync extends Sync { final void lock() { acquire(1); } // AbstractQueuedSynchronizer.acquire(int arg) public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); } protected final boolean tryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { // 1. 和非公平鎖相比,這裏多了一個判斷:是否有線程在等待 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; } }
非公平鎖的 lock 方法:線程
static final class NonfairSync extends Sync { final void lock() { // 2. 和公平鎖相比,這裏會直接先進行一次CAS,成功就返回了 if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } // AbstractQueuedSynchronizer.acquire(int arg) public final void acquire(int arg) { if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); } protected final boolean tryAcquire(int acquires) { return nonfairTryAcquire(acquires); } } /** * Performs non-fair tryLock. tryAcquire is implemented in * subclasses, but both need nonfair try for trylock method. */ final boolean nonfairTryAcquire(int acquires) { final Thread current = Thread.currentThread(); int c = getState(); if (c == 0) { // 這裏沒有對阻塞隊列進行判斷 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; }
總結:公平鎖和非公平鎖只有兩處不一樣:code
非公平鎖在調用 lock 後,首先就會調用 CAS 進行一次搶鎖,若是這個時候恰巧鎖沒有被佔用,那麼直接就獲取到鎖返回了。
非公平鎖在 CAS 失敗後,和公平鎖同樣都會進入到 tryAcquire 方法,在 tryAcquire 方法中,若是發現鎖這個時候被釋放了(state == 0),非公平鎖會直接 CAS 搶鎖,可是公平鎖會判斷等待隊列是否有線程處於等待狀態,若是有則不去搶鎖,乖乖排到後面。
公平鎖和非公平鎖就這兩點區別,若是這兩次 CAS 都不成功,那麼後面非公平鎖和公平鎖是同樣的,都要進入到阻塞隊列等待喚醒。orm
相對來講,非公平鎖會有更好的性能,由於它的吞吐量比較大。固然,非公平鎖讓獲取鎖的時間變得更加不肯定,可能會致使在阻塞隊列中的線程長期處於飢餓狀態。blog