ReentrantLock原理分析

       ReentrantLock 重入鎖是對 synchronized 的一種補充,ReentrantLock 提供了可定時、可輪詢的與可中斷的鎖獲取操做,公平隊列,以及非塊結構的鎖。與 synchronized 相比, ReentrantLock 更加靈活可控,伸縮性更好。ReentrantLock 的非公平鎖性能也比 synchronized 更好。
      經過對 CAS 的瞭解,咱們知道 CAS 底層也是經過排它鎖實現的,只不過 CAS 是 CPU 觸發的,效率更高。ReentrantLock 實現方式和 AtomicInteger 方式相似,不過 ReentrantLock 藉助 AbstractQueuedSynchronizer 類來實現獨佔鎖的功能。

ReentrantLock 主要方法以下:java

  1. ReentrantLock 構造函數,傳入 boolean 參數標明是公平鎖仍是非公平鎖,默認是非公平鎖;
  2. lock 獲取鎖,lock 獲取鎖若是成功直接返回,若是失敗則阻塞等待;
  3. lockInterruptibly 支持中斷獲取鎖,lock 獲取鎖若是成功直接返回,若是失敗則阻塞等待,並支持中斷操做,
  4. tryLock 獲取鎖,tryLock 沒有設置超時時間時,獲取鎖成功或者失敗都直接返回,tryLock 設置超時時間時,最多等待超時時間後返回結果,並支持中斷操做;
  5. unlock 釋放鎖,unlock 釋放鎖喚醒等待隊列的第一個線程。


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

相關文章
相關標籤/搜索