【JDK源码分析系列】ReentrantLock 源码分析
发布日期:2021-05-07 20:54:20 浏览次数:25 分类:精选文章

本文共 8273 字,大约阅读时间需要 27 分钟。

【JDK源码分析系列】ReentrantLock 源码分析

【1】内部同步类 -- Sync

/**     * 内部类变量     * ReentrantLock 可重入锁的实现实际上是基于内部类 Sync 实现的;     */    private final Sync sync;     /**      * Sync 类继承 AbstractQueuedSynchronizer      * 通过实现 AbstractQueuedSynchronizer 中的可重写方法实现可重入锁的功能      *      * 静态内部类 :      * 1. 可以通过静态内部类的全类名来调用静态内部类的静态属性(外部类名.静态内部类名.属性)      * 2. 可以通过静态内部类的全类名来调用静态内部类的静态方法(外部类名.静态内部类名.方法)      * 3. 不能通过类静态内部类的全类名来调用内部类的非静态属性和方法      * 4. 可以通过创建内部类实例来调用静态内部类的非静态属性和方法      *      * 5. 可以直接调用外部类的静态属性      * 6. 可以直接调用外部类的静态方法      * 7. 无法直接调用外部类的非静态属性      * 8. 无法直接调用外部类的非静态方法      * 9. 可以通过创建外部类实例来调用外部类的非静态属性      * 10.可以通过创建外部类实例来调用外部类的非静态方法      */    abstract static class Sync extends AbstractQueuedSynchronizer {        private static final long serialVersionUID = -5179523762034025860L;         /**          * 提供抽象方法,方便子类重写,实现加锁的功能          */        abstract void lock();         /**          * 非公平的获取锁的方法          * tryAcquire 在子类中实现,实现 tryAcquire 时需要使用到该方法          */        final boolean nonfairTryAcquire(int acquires) {            // 获取当前线程            final Thread current = Thread.currentThread();            /**             * 获取 state,state 为定义在 AbstractQueuedSynchronizer 类中的字段;             * 此处 state 用于记录锁重入的次数             */            int c = getState();            /**             * 若 state 为 0,则将 acquires 赋值给 state              * 并将当前线程设置为独断式访问权限的拥有者             */            if (c == 0) {                if (compareAndSetState(0, acquires)) {                    setExclusiveOwnerThread(current);                    return true;                }            }            /**             * 若 state 不为 0,则表明当前锁已经被获取             * 判断当前线程是否为锁的拥有者,若是则增加锁重入的次数             */            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;        }        /**         * 释放锁方法         * 由于锁支持重入,则释放锁时需要减少锁的同步状态         * 当锁的同步状态减少到0时,即可释放锁,即设置独占式访问的拥有者为 null         * 释放锁必须确保只能是锁的拥有者释放锁         */        protected final boolean tryRelease(int releases) {            int c = getState() - releases;            if (Thread.currentThread() != getExclusiveOwnerThread())                throw new IllegalMonitorStateException();            boolean free = false;            if (c == 0) {                free = true;                setExclusiveOwnerThread(null);            }            setState(c);            return free;        }        /**         * 该方法用于判断当前线程是否是锁的拥有者         */        protected final boolean isHeldExclusively() {            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;        }        /**         * 该方法用于判断锁的状态         * 当锁的同步状态非 0 则可以认为锁是锁定的         */        final boolean isLocked() {            return getState() != 0;        }	 /**	  * 该方法用于从流中读取对象并创建	  */        private void readObject(java.io.ObjectInputStream s)            throws java.io.IOException, ClassNotFoundException {            s.defaultReadObject();            setState(0); // reset to unlocked state        }    }

【2】非公平锁的同步类 -- NonfairSync

/**     * 非公平锁的同步类     */    static final class NonfairSync extends Sync {        private static final long serialVersionUID = 7316153563782823691L;        /**         * 加锁处理         */        final void lock() {            /**             * CAS 方式设置状态值             * 若比较值为 0,表明尚未有线程获取到同步状态:             * 此时尝试将同步状态设置为 1,即尝试抢占同步状态;             *              * 若比较值非 0,表明当前存在获取同步状态的线程;             * 此时尝试将同步状态设置为 1,将会失败;             */            if (compareAndSetState(0, 1))            /**             * 当成功获取同步状态则将当前线程设置为锁的持有者;             */                setExclusiveOwnerThread(Thread.currentThread());            else            /**             * 当获取同步状态失败,则调用 AbstractQueuedSynchronizer 类中的              * public final void acquire(int arg) 方法,再次尝试获取同步状态,             * 若仍然获取同步状态失败则加入同步队列不断自旋等待获取同步状态成功的时机;             */                acquire(1);        }        /**         * 该方法为 AbstractQueuedSynchronizer 类中需要重写的方法,         * 该方法重写后会结合 AbstractQueuedSynchronizer 类中的模板方法,         * 实现基于同步队列的方式获取同步状态的操作;         *          * 在非公平获取锁的方式中实际调用的是内部类 Sync 中的          * final boolean nonfairTryAcquire(int acquires) 方法;         */        protected final boolean tryAcquire(int acquires) {            return nonfairTryAcquire(acquires);        }    }

【3】公平锁的同步类 -- FairSync

/**     * 公平锁的同步结构     */    static final class FairSync extends Sync {        private static final long serialVersionUID = -3000897897090466540L;        /**         * 加锁处理         */        final void lock() {        /**         * 此处为了保证获取同步状态的公平性,直接调用 AbstractQueuedSynchronizer 类中的          * public final void acquire(int arg) 方法尝试获取同步状态,         * 若获取同步状态失败则加入同步队列不断自旋等待获取同步状态成功的时机;         * 加入队列可以保证获取锁的顺序性;         */            acquire(1);        }        /**         * 该方法为 AbstractQueuedSynchronizer 类中需要重写的方法,         * 该方法重写后会结合 AbstractQueuedSynchronizer 类中的模板方法,         * 实现基于同步队列的方式获取同步状态的操作;         */        protected final boolean tryAcquire(int acquires) {            // 获取当前线程;            final Thread current = Thread.currentThread();            // 获取同步状态;            int c = getState();            /**             * 同步状态为 0,表明尚未有线程获取到同步状态;             * hasQueuedPredecessors() 方法为 AbstractQueuedSynchronizer 类中的             * public final boolean hasQueuedPredecessors() 方法,用于判断同步队列中             * 是否存在排列在当前线程之前的线程;             *              * !hasQueuedPredecessors() : 表明只有当当前线程是队列的首节点时,             * 才能够尝试获取同步状态,             * 这样保证了获取锁的操作的顺序性;             * compareAndSetState(0, acquires) : 表明竞争获取同步状态的操作;             * 若成功则将当前线程设置为锁的持有者;             */            if (c == 0) {                if (!hasQueuedPredecessors() &&                    compareAndSetState(0, acquires)) {                    setExclusiveOwnerThread(current);                    return true;                }            }            /**             * current == getExclusiveOwnerThread() : 表明此锁是被当前线程所拥有;             * 此处做重入处理,主要是更新了同步状态;             */            else if (current == getExclusiveOwnerThread()) {                int nextc = c + acquires;                if (nextc < 0) // 防止溢出;                    throw new Error("Maximum lock count exceeded");                // 设置同步状态;                setState(nextc);                return true;            }            // 上述判断条件都不满足则返回获取同步状态失败;            return false;        }    }

【4】提供给外部的方法

/**     * 构造方法,默认构造非公平方式获取同步状态;     */    public ReentrantLock() {        sync = new NonfairSync();    }    /**     * 构造方法,此方法按照指定的方式获取同步状态;     */    public ReentrantLock(boolean fair) {        sync = fair ? new FairSync() : new NonfairSync();    }        /**     * ReentrantLock 类的加锁方法;     * 调用内部类 Sync 中的 abstract void lock() 方法,     * 该方法会在 Sync 类的子类中重写,     * 从而实现公平或非公平方式获取同步状态的操作;     */    public void lock() {        sync.lock();    }    /**     * 加锁并能够响应中断;     * 实际是调用 AbstractQueuedSynchronizer 类的      * public final void acquireInterruptibly(int arg) 实现的;     */    public void lockInterruptibly() throws InterruptedException {        sync.acquireInterruptibly(1);    }    /**     * tryLock() : 非公平式获取同步状态的方法;     */    public boolean tryLock() {        return sync.nonfairTryAcquire(1);    }    /**     * tryLock(long timeout, TimeUnit unit) : 尝试获取锁的方法     * 同时响应中断并由超时限制;     */    public boolean tryLock(long timeout, TimeUnit unit)            throws InterruptedException {        return sync.tryAcquireNanos(1, unit.toNanos(timeout));    }    /**     * 释放锁操作     */    public void unlock() {        sync.release(1);    }

参考致谢

本博客为博主的学习实践总结,并参考了众多博主的博文,在此表示感谢,博主若有不足之处,请批评指正。
【1】Java并发编程的艺术

上一篇:【JDK源码分析系列】ReentrantReadWriteLock 源码分析
下一篇:【JDK源码分析系列】AbstractQueuedSynchronizer 源码分析 -- 锁的获取与释放

发表评论

最新留言

感谢大佬
[***.8.128.20]2025年04月16日 21时13分53秒