ReentrantLock 类 源代码详细解释

56 阅读4分钟

什么是可重入锁,怎么理解可重入?

所谓的可重入就是一个线程获取到了锁之后,同一个线程还是想要再次的获取到这个锁,那么这个锁可以再次的被获取到,那么这个锁就是可重入锁。否则这个,锁就是不可重入锁。

ReentrantLock 实现原理

public class ReentrantLock implements Lock, java.io.Serializable {
    ......
        
        
    ......
}

在 idea 打开这个类的时候,在 ReentrantLock 中存在三个内部类以及自己的一系列方法。一个公平锁的内部类,一个非公平锁的内部类,一个 Sync 类继承了抽象队列同步器,继承了相关的方法,可以使用多个等待条件实现同步

在类的顶部可以看到实现了 Lock 接口,也就是有了基本的显式声明锁,获取锁的能力。同时实现了序列化接。Serialization(序列化)是一种将对象以一连串的字节描述的过程;反序列化deserialization是一种将这些字节重建成一个对象的过程。 对象数据需要在网络中传输的时候,或者将 Java 独享保存早磁盘的时候,需要使用序列化以及反序列化。

构造方法的实现

    // 创造出来一个不公平的锁
    /**
     * Creates an instance of {@code ReentrantLock}.
     * This is equivalent to using {@code ReentrantLock(false)}.
     */
    public ReentrantLock() {
        sync = new NonfairSync();
    }

    // 创建出来一个公平锁
    /**
     * Creates an instance of {@code ReentrantLock} with the
     * given fairness policy.
     *
     * @param fair {@code true} if this lock should use a fair ordering policy
     */
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

其他方法的实现

查看源代码的时候注意到:在这个类中的相关方法只是一个语法糖,真正调用的是内部类 Sync 引用调用的方法。所以说 ReentrantLock 就是一个基于 AQS 创建出来的可重入锁。一方面,ReentrantLock 具有自己特定的加锁,解锁的方法,另外一方便,由于这个类继承了 AQS ,所以具有 AQS 的特性。

ReentrantLock 核心 - Sync - 核心方法

    /**
     * Base of synchronization control for this lock. Subclassed
     * into fair and nonfair versions below. Uses AQS state to
     * represent the number of holds on the lock.
     */
    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;

        /**
         * Performs {@link Lock#lock}. The main reason for subclassing
         * is to allow fast path for nonfair version.
         */
        // 定义抽象方法,获取锁
        abstract void lock();

        /**
         * Performs non-fair tryLock.  tryAcquire is implemented in
         * subclasses, but both need nonfair try for trylock method.
         */
        /**
           尝试获取到锁,拿到锁的话返回 true, 否则返回 false;
           如果是当前线程已经获取到了锁,是可以重入的,这个是重入的核心
        */
        final boolean nonfairTryAcquire(int acquires) {
       
            // 获取当前的线程,就是什么线程调用了这个方法
            final Thread current = Thread.currentThread();
            
            // state 是 AQS 提供的变量,通过这个变量可以控制锁被线程获取的次数
            int c = getState();
            
            
            if (c == 0) {
                // 以为 c== 0 ,这个时候锁还是没有被线程获取到的
                if (compareAndSetState(0, acquires)) {
                    // 由于锁还没有被使用,这个直接把锁给当前的线程
                    setExclusiveOwnerThread(current);
                    // 当前的线程获取到了锁,那么返回 true 即可
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                // current == getExclusiveOwnerThread() 
                // 当前线程和前面已经获取到锁的线程是一个线程,那么下面实现锁的重入
                
                // 当前线程持有锁的时候, state + 1
                int nextc = c + acquires;
                
                // 记录所重入的次数
                // 拥有锁的线程数量大于 MAX_INTEGER 会变为负数,所以是 overflow
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                
                // AQS 的 state 随着重入次数的增加而增加
                setState(nextc);
                return true;
            }
            
            // 如果一个线程既不是第一次获取到锁,也不能实现重入,那么就返回 false
            return false;
        }

        protected final boolean tryRelease(int releases) {
            // 计算一个线程释放了锁之后的 state 的值
            int c = getState() - releases;
            
            // 持有锁的线程不是当前的线程,那么无法释放资源的,谁拿了谁才能释放锁
            if (Thread.currentThread() != getExclusiveOwnerThread())
                // 抛出来异常,没有拿锁,竟然想要释放锁,不被允许
                throw new IllegalMonitorStateException();
            
            boolean free = false;
            
            // state == 0 的时候,需要将 free 改为 true 表示已经释放了
            // 同时把持有者的信息抹掉,其他的线程才能继续的获取到锁
            if (c == 0) {
                free = true;  // 标志位修改
                setExclusiveOwnerThread(null); // 持有锁的信息抹掉
            }
            
            // 因为持有锁的线程把锁放了,这里的 state 也就是变为了 0 
            setState(c);
            
            // 释放成功,没有线程拿着这个锁了,free 就是 true, 其他的线程可以使用这个锁了
            return free;
        }

        protected final boolean isHeldExclusively() {
            // While we must in general read state before owner,
            // we don't need to do so to check if current thread is owner
            return getExclusiveOwnerThread() == Thread.currentThread();
        }

        final ConditionObject newCondition() {
            return new ConditionObject();
        }

        // Methods relayed from outer class

        final Thread getOwner() {
            return getState() == 0 ? null : getExclusiveOwnerThread();
        }

        final int getHoldCount() {
            return isHeldExclusively() ? getState() : 0;
        }

        final boolean isLocked() {
            return getState() != 0;
        }

        /**
         * Reconstitutes the instance from a stream (that is, deserializes it).
         */
        private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
            s.defaultReadObject();
            setState(0); // reset to unlocked state
        }
    }

ReentrantLock 核心 - NonfairSync

    /**
     * Sync object for non-fair locks
     */
    /**
       这个是 ReentrantLock 中的非公平锁的实现源码,默认使用的是非公平锁
       
    */
    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() {
            // 做一个 CAS 操作, CAS 成功,说明以前没有线程获取到锁
            // 将当前线程独占锁,圈地
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                // 无法获取到锁,说明锁已经被占用了
                // 调用下面的 acquare() 方法
                // 注意:在 acquare() 中后面还有一系列的方法,这里没有展示出来
                // 执行的逻辑就是:
                //	 1.持有锁的线程是自己,那么重入即可
                // 	 2.持有锁的线程不是自己,那么去 AQS 中排队
                //   3.在 AQS 中排队使用的是双向链表。addWaiter() 方法中创造结点,把需要排队的线程信息放进去
                // 		  按照尾插法将需要排队的线程放进去 Node 结点中保存
                acquire(1);
        }

        /**
           在非公平锁中获取锁还有下面的一种方式,使用 tryAcquire() 
           走的是 nonfairTryAcquire() 这个方法
        */
        protected final boolean tryAcquire(int acquires) {
            // 在 nonfairTryAcquire(1) 方法中传递 1 进去
            // 进去到上面解析的代码中,存在两种情况:
            //     1.持有锁的线程是自己,那么重入即可
            //     2.持有锁的线程不是自己,那么去 AQS 中排队
            return nonfairTryAcquire(acquires);
        }
    }

ReentrantLock 核心 - FairSync

按照排队的方式获取锁,FIFO 的原则,十分的公平

    /**
     * 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) {
                
                /**
                 * 公平锁与非公平锁很大的一个区别是:
                 * 在尝试获取锁的时候,如果AQS的同步队列中有其他线程在等待获取锁
                 * 则尝试获取锁失败,需要进入AQS的同步队列排队
                 * hasQueuedPredecessors方法判断AQS的同步队列是否有线程在等待
                 */
                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;
        }
    }

ReentrantLock() 类中非内部类剩下来的方法 0 部分省略

整体的代码执行了流程就是:

使用 Sync 类型的对象,调用相关的 lock() 的等方法。

Sync 对象是基于公平锁实现还是基于非公平锁实现取决于构造方法。

这样通过构造方法实现了对于公平锁以及非公平锁的锁对象的控制。

    /**
     * Creates an instance of {@code ReentrantLock}.
     * This is equivalent to using {@code ReentrantLock(false)}.
     */
    public ReentrantLock() {
        sync = new NonfairSync();
    }

    /**
     * Creates an instance of {@code ReentrantLock} with the
     * given fairness policy.
     *
     * @param fair {@code true} if this lock should use a fair ordering policy
     */
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

    /**
     * Acquires the lock.
     *
     * <p>Acquires the lock if it is not held by another thread and returns
     * immediately, setting the lock hold count to one.
     *
     * <p>If the current thread already holds the lock then the hold
     * count is incremented by one and the method returns immediately.
     *
     * <p>If the lock is held by another thread then the
     * current thread becomes disabled for thread scheduling
     * purposes and lies dormant until the lock has been acquired,
     * at which time the lock hold count is set to one.
     */
    public void lock() {
        sync.lock();
    }


    public boolean tryLock() {
        return sync.nonfairTryAcquire(1);
    }
    public boolean tryLock(long timeout, TimeUnit unit)
            throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }

    /**
     * Attempts to release this lock.
     *
     * <p>If the current thread is the holder of this lock then the hold
     * count is decremented.  If the hold count is now zero then the lock
     * is released.  If the current thread is not the holder of this
     * lock then {@link IllegalMonitorStateException} is thrown.
     *
     * @throws IllegalMonitorStateException if the current thread does not
     *         hold this lock
     */
    public void unlock() {
        sync.release(1);
    }

     
    public Condition newCondition() {
        return sync.newCondition();
    }

    public int getHoldCount() {
        return sync.getHoldCount();
    }

    public boolean isHeldByCurrentThread() {
        return sync.isHeldExclusively();
    }

    /**
     * Queries if this lock is held by any thread. This method is
     * designed for use in monitoring of the system state,
     * not for synchronization control.
     *
     * @return {@code true} if any thread holds this lock and
     *         {@code false} otherwise
     */
    public boolean isLocked() {
        return sync.isLocked();
    }

    /**
     * Returns {@code true} if this lock has fairness set true.
     *
     * @return {@code true} if this lock has fairness set true
     */
    public final boolean isFair() {
        return sync instanceof FairSync;
    }


    protected Thread getOwner() {
        return sync.getOwner();
    }


    public final boolean hasQueuedThreads() {
        return sync.hasQueuedThreads();
    }


    public final boolean hasQueuedThread(Thread thread) {
        return sync.isQueued(thread);
    }


    public final int getQueueLength() {
        return sync.getQueueLength();
    }

    ......
    ......
    protected Collection<Thread> getQueuedThreads() {
        return sync.getQueuedThreads();
    }

小结

本文详细的介绍了 ReentrantLock 的源代码,本文从四个方面介绍:三个 ReentrantLock 的内部类以及 ReentrantLock 类本身的方法。ReentrantLock 的实现原理其实是基于 AQS 的,同时 ReentrantLock 实例化构造对象的时候,可以选择是公平锁还是不公平锁。