• ReentrantLock(重入锁)简单源码分析


    1.ReentrantLock是基于AQS实现的一种重入锁。

    2.先介绍下公平锁/非公平锁

    公平锁

    • 公平锁是指多个线程按照申请锁的顺序来获取锁。

    非公平锁

    • 非公平锁是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁。有可能,会造成优先级反转或者饥饿现象。

    3.重入锁/不可重入锁

    可重入锁:广义上的可重入锁指的是可重复可递归调用的锁,在外层使用锁之后,在内层仍然可以使用,并且不发生死锁(前提得是同一个对象或者class),这样的锁就叫做可重入锁。

    不可重入锁:不可重入锁,与可重入锁相反,不可递归调用,递归调用就发生死锁。

    4.统一入口

     //获取锁。
        @Override
        public void lock() {
            sync.lock();
        }
    
    
        //获取锁,响应中断
        @Override
        public void lockInterruptibly() throws InterruptedException {
            sync.acquireInterruptibly(1);
        }
    
        //仅在调用时锁未被另一个线程保持的情况下,才获取该锁。
        @Override
        public boolean tryLock() {
            return sync.nonfairTryAcquire(1);
        }
    
    
        //如果锁在给定等待时间内没有被另一个线程保持,且当前线程未被 中断,则获取该锁。
        @Override
        public boolean tryLock(long timeout, TimeUnit unit)
                throws InterruptedException {
            return sync.tryAcquireNanos(1, unit.toNanos(timeout));
        }
    
        //试图释放此锁。
        @Override
        public void unlock() {
            sync.release(1);
        }

    ReentrantLock默认是非公平模式,可以通过构造函数指定模式。

    /**
         * 构造函数,默认非公平锁
         */
        public ReentrantLock() {
            sync = new NonfairSync();
        }
    
        /**
         * 构造函数,通过布尔参数设置是否是公平锁
         * @param fair
         */
        public ReentrantLock(boolean fair) {
            sync = fair ? new FairSync() : new NonfairSync();
        }

    4.非公平模式的加锁和解锁

     加锁:

    //获取锁。
        @Override
        public void lock() {
            sync.lock();
        }

    然后调用NonfairSync的lock方法:

    /**
             * 加锁
             */
            @Override
            final void lock() {
                //以cas方式尝试将AQS中的state从0更新为1
                if (compareAndSetState(0, 1)) {
                    //获取锁成功则将当前线程标记为持有锁的线程,然后直接返回
                    setExclusiveOwnerThread(Thread.currentThread());
                } else {
                    acquire(1);
                }
            }

    如果设置state失败,则调用NonfairSync的tryAcquire方法

    @Override
            protected final boolean tryAcquire(int acquires) {
                return nonfairTryAcquire(acquires);
            }

    然后调用Sync的nonfairTryAcquire方法:

    /**
             * 非公平模式的情况下获取同步状态
             * @param acquires
             * @return
             */
            final boolean nonfairTryAcquire(int acquires) {
                //获取当前线程实例
                final Thread current = Thread.currentThread();
                //获取同步state变量的值,即当前锁被重入的次数
                int c = getState();
                //state为0,说明当前锁未被任何线程持有
                if (c == 0) {
                    //以cas方式获取锁
                    if (compareAndSetState(0, acquires)) {
                        //将当前线程标记为持有锁的线程
                        setExclusiveOwnerThread(current);
                        //获取锁成功,非重入
                        return true;
                    }
                    //当前线程就是持有锁的线程,说明该锁被重入了,实现重入
                } else if (current == getExclusiveOwnerThread()) {
                    //计算state变量要更新的值
                    int nextc = c + acquires;
                    if (nextc < 0) // overflow
                        throw new Error("Maximum lock count exceeded");
                    //非同步方式更新state值
                    setState(nextc);
                    //获取锁成功,重入
                    return true;
                }
                //尝试获取锁失败
                return false;
            }

    这边体现了锁的重入,用state的次数表示锁被线程重入了state次。

    else if (current == getExclusiveOwnerThread()) {
                    //计算state变量要更新的值
                    int nextc = c + acquires;
                    if (nextc < 0) // overflow
                        throw new Error("Maximum lock count exceeded");
                    //非同步方式更新state值
                    setState(nextc);
                    //获取锁成功,重入
                    return true;
                }

     解锁

    //试图释放此锁。
        @Override
        public void unlock() {
            sync.release(1);
        }

    然后调用Sync的tryRelease方法:

    /**
             * 释放同步状态
             * @param releases
             * @return
             */
            @Override
            protected final boolean tryRelease(int releases) {
                //计算待更新的state值
                int c = getState() - releases;
                //判断当前线程是否独占
                if (Thread.currentThread() != getExclusiveOwnerThread()) {
                    throw new IllegalMonitorStateException();
                }
                //是否释放同步状态成功的标志
                boolean free = false;
                //待更新的state值为0,说明持有锁的线程未重入,一旦释放锁其他线程将能获取
                if (c == 0) {
                    free = true;
                    //清除锁的持有线程标记
                    setExclusiveOwnerThread(null);
                }
                //更新state值
                setState(c);
                return free;
            }
     锁的最终释放要去锁对于获取进行计数自增,计算表示当前锁被重复获取的次数,而锁被释放时,计数自减,当计数为0时表示已经释放成功。

    5.公平模式的加锁和解锁

     加锁:

    @Override
            protected final boolean tryAcquire(int acquires) {
                //获取当前线程实例
                final Thread current = Thread.currentThread();
                //获取同步state变量的值,即当前锁被重入的次数
                int c = getState();
                //state为0,说明当前锁未被任何线程持有
                if (c == 0) {
                    /**
                     * 1.判断同步队列中当前节点是否有前驱节点
                     * 2. 以cas方式获取锁
                     */
                    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");
                    //非同步方式更新state值
                    setState(nextc);
                    //获取锁成功,重入
                    return true;
                }
                //尝试获取锁失败
                return false;
            }

    对于非公平锁,只要cas设置同步状态成功,则表示当前线程获取了锁,而公平锁则不同,公平锁的获取增加了hasQueuedPredecessors的判断,即加入了判断同步队列中当前节点是否有前驱节点,

    如果返回true,则表示有线程比当前线程更早滴请求获取锁,因此需要等待前驱线程获取并释放锁之后才能继续获取锁。

      解锁:同公平锁的解锁方式

     

     

  • 相关阅读:
    redis方法中文解释
    简单redis队列实现
    PHP中常用的字符串操作【转】
    SQL循环语句
    crontable 实例
    自动以当前时间命名文件
    tar命令详解
    PHP 数据类型验证和获取
    Nginx 配置文件nginx.conf的完整配置说明
    sql server DateFormat(转)
  • 原文地址:https://www.cnblogs.com/ql211lin/p/10439108.html
Copyright © 2020-2023  润新知