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

相关文章
相关标签/搜索