zoukankan      html  css  js  c++  java
  • AQS之可重入锁ReentrantLock原理

    一、经典故事

    村子里面,有一口井水。水质很好,村民们都想打井里的水。
    村长这时就制定了规则:
    井边安排一个看井人,维护打水的秩序。
    打水时,以家庭为单位,哪个家庭任何人先到井边,就可以先打水,而且如果一个家庭占到了打水权,其家人这时候过来打水不用排队。
    而那些没有抢占到打水权的人,一个一个挨着在井边排成一队,先到的排在前面。
    二、图析ReentrantLock
    /**
         * 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();
        }

    由构造函数中可知,ReentrantLock默认采用的是非公平锁模式,之所以默认才用这种模式,是因为:

    非公平锁减少线程挂起的几率,后来的线程有一定的几率直接获取锁。

    1. 非公平模式:
     
            final void lock() {
                if (compareAndSetState(0, 1)) // CAS尝试获取锁权
                    setExclusiveOwnerThread(Thread.currentThread());
                else
                    acquire(1);
            }
            
            public final void acquire(int arg) {
              if (!tryAcquire(arg) &&
                acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
                selfInterrupt();
            }
    
            protected final boolean tryAcquire(int acquires) {
                return nonfairTryAcquire(acquires);
            }
            
            final boolean nonfairTryAcquire(int acquires) {
                final Thread current = Thread.currentThread();
                int c = getState();
                if (c == 0) {
                    // 这里区别公平锁,直接CAS再次尝试获取锁权
                    if (compareAndSetState(0, acquires)) {
                        setExclusiveOwnerThread(current);
                        return true;
                    }
                }
                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;
            }
     

     2. 公平锁模式:

         final void lock() {
                // 按部就班,看排队情况
                acquire(1);
            }
            public final void acquire(int arg) {
                if (!tryAcquire(arg) &&
                acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
                selfInterrupt();
            }
            protected final boolean tryAcquire(int acquires) {
                final Thread current = Thread.currentThread();
                int c = getState();
                if (c == 0) {
                    // 前面没人排队才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");
                    setState(nextc);
                    return true;
                }
                return false;
            }

     至于:

         public final void acquire(int arg) {
            if (!tryAcquire(arg) &&
                acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
                selfInterrupt();
            }
    acquireQueued(addWaiter(Node.EXCLUSIVE), arg):入队
    selfInterrupt():阻塞

    三、比对打水的故事

    问看井人:空闲情况下,所有家庭问的结果,只能有一个成功。(CAS)
    可重入锁:家庭为单位(每一个人同属一个线程),家庭获取到了打水权,家庭里所有人都获取到了打水权。
    非公平模式:新到的家庭代表,直接去问看井人井是否空闲了
                                 1. 空闲了就获取打水权
                                 2. 不空闲,再看一眼有没有人在打水?
                                         2.1 没人,再去问看井人
                                         2.2 有人,是不是自家人?是则去打水,否则去排队
    公平锁模式:新到的人(比如叫张三),先肉眼看是否有人在打水?
                                 1.   没人的话再看前面有没有人排队
                                              1.1 有人排队,乖乖的去排队
                                              1.2 没人排队,去问看井人决定是否成功获取打水权
                                 2.   有人在打水,问问打水人跟张三是否一家的?
                                               2.1 是,可以来打水
                                               2.2 否,去排队

     参考资料:

    https://www.jianshu.com/p/3204049fbf14

    https://www.jianshu.com/p/f584799f1c77

    每一步脚印都要扎得深一点!
  • 相关阅读:
    mysql 创建数据库的基本操作
    MySQL的数据类型 及注意事项
    在执行 pip install 时遇到错误:python setup.py egg_info Check the logs for full command output
    python3.8-运行jupyter 报raise NotImplementedError
    执行python 爬虫脚本时提示bs4.FeatureNotFound: Couldn't find a tree builder with the features you requested: lxml. Do you need to install a parser library?
    Python:lambda表达式和yield关键字理解与使用讲解
    百度paddle框架学习(二):使用经典VGG网络完成人脸口罩判别
    深度学习中的梯度
    C++ OpenCV学习笔记(持续更新)
    Tensorflow常见报错
  • 原文地址:https://www.cnblogs.com/bloodthirsty/p/12118888.html
Copyright © 2011-2022 走看看