• JDK8 ReentrantReadWriteLock源码分析


    ReentrantReadWriteLock中的state代表了读锁的数量和写锁的持有与否,整个结构如下: 
     
     
    在本文中对AQS部分源码不在讲解,可以参考  AbstractQueuedSynchronizer源码分析    
    首先从读锁开始看起
     readLock.lock()
       
    /**
      * 获取读锁
      * 如果写锁没有被其他线程占有,获取读锁后立即返回
      * 如果写锁被其他线程占有,则当前线程挂起直到获取到读锁
      **/
     public void lock() {
                sync.acquireShared(1);
            }
    
      public final void acquireShared(int arg) {
            if (tryAcquireShared(arg) < 0)
                doAcquireShared(arg);
        }
    
      
      /**
        * 如果写锁被占用则失败
        * 否则该线程具有获取锁的资格,首先根据不同的队列策略判断是否需要被挂起,如果不需要
        * 则通过CAS操作尝试获取锁,如果可以获取锁则需要更新计数;注意在这步操作中不进行重入处理
        * 如果线程需要挂起,或达到上限或CAS操作失败都会进入完整获取读锁的循环中
        **/
      protected final int tryAcquireShared(int unused) {
                //当前线程
                Thread current = Thread.currentThread();
                //获取同步状态
                int c = getState();
                //写锁被占用,且不是当前线程;则获取读锁失败
                if (exclusiveCount(c) != 0 &&
                    getExclusiveOwnerThread() != current)
                    return -1;
                 //获取读锁目前被占用数量   
                int r = sharedCount(c);
                //如果读取器不需要排队且读锁占用数量没有达到上限则通过CAS尝试获取读锁
                if (!readerShouldBlock() &&
                    r < MAX_COUNT &&
                    compareAndSetState(c, c + SHARED_UNIT)) {
                    //如果读区锁为0,表示还没有任何读取器占用锁,则将当前线程设置为第一个读取器,其持有锁的数量为1个
                    if (r == 0) {
                        firstReader = current;
                        firstReaderHoldCount = 1;
                        //如果已经有线程占用读锁,且当前线程和第一个占用读锁线程相同则其持有锁的数量自增
                    } else if (firstReader == current) {
                        firstReaderHoldCount++;
                    } else {
                       //如果已经有线程占用了读锁,但是不是当前线程
                       //最后一个成功获取读锁的线程占用读锁的数量计数器
                        HoldCounter rh = cachedHoldCounter;
                        //如果不为null且不是当前线程,则将其更新为当前线程的读锁计数器
                        if (rh == null || rh.tid != getThreadId(current))
                            cachedHoldCounter = rh = readHolds.get();
                         //如果rh获取锁的数量为0则表示rh是新建对象,将其加入到readHolds中   
                        else if (rh.count == 0)
                            readHolds.set(rh);
                            //持有读锁数量自增
                        rh.count++;
                    }
                    //返回1
                    return 1;
                }
                //如果读锁需要排队,或者达到读锁上限或者CAS失败都会进行充分获取锁重试循环
                return fullTryAcquireShared(current);
            }
    
    
            /**
              * 获取读锁的完整版本,处理CAS遗漏以及在上一步操作中没有处理的重入问题
              *
              **/
            final int fullTryAcquireShared(Thread current) {
               
                HoldCounter rh = null;
               
                for (;;) {
                   //获取同步状态
                    int c = getState();
                    //如果写锁被占用且不是当前线程则返回-1
                    if (exclusiveCount(c) != 0) {
                        if (getExclusiveOwnerThread() != current)
                            return -1;
                     //写锁没有被占用判断当前线程是否需要挂起,如果需要挂起   
                    } else if (readerShouldBlock()) {
                        // Make sure we're not acquiring read lock reentrantly
                        if (firstReader == current) {
                            // assert firstReaderHoldCount > 0;  
                        } else {
                           //当前第一个读取器不是当前线程,即别的线程占有了读锁
                            if (rh == null) {
                            //将最后一个成功获取读锁的线程计数器赋值给rh
                                rh = cachedHoldCounter;
                                //如果还没有线程获取读锁,或者最后一个获取读锁的不是当前线程则获取当前线程的计数器
                                if (rh == null || rh.tid != getThreadId(current)) {
                                    rh = readHolds.get();
                                    //如果当前线程计数器,中获取读锁的数量为0则将其删除
                                    if (rh.count == 0)
                                        readHolds.remove();
                                }
                            }
                            //当前线程没有获取到读锁
                            if (rh.count == 0)
                                return -1;
                        }
                    }
                    //如果读锁达到上限抛出异常
                    if (sharedCount(c) == MAX_COUNT)
                        throw new Error("Maximum lock count exceeded");
                      //CAS操作,将写锁清0,如果成功则表示写锁没有被占用
                    if (compareAndSetState(c, c + SHARED_UNIT)) {
                        if (sharedCount(c) == 0) {
                            firstReader = current;
                            firstReaderHoldCount = 1;
                        } else if (firstReader == current) {
                            firstReaderHoldCount++;
                        } else {
                            if (rh == null)
                                rh = cachedHoldCounter;
                            if (rh == null || rh.tid != getThreadId(current))
                                rh = readHolds.get();
                            else if (rh.count == 0)
                                readHolds.set(rh);
                            rh.count++;
                            cachedHoldCounter = rh; // cache for release
                        }
                        return 1;
                    }
                }
            }
    
             
    readLock.unlock()

     public void unlock() {
                sync.releaseShared(1);
            }
    
     public final boolean releaseShared(int arg) {
            if (tryReleaseShared(arg)) {
                doReleaseShared();
                return true;
            }
            return false;
        }
    
    
     protected final boolean tryReleaseShared(int unused) {
              //当前线程
                Thread current = Thread.currentThread();
                //第一个读取器是当前线程
                if (firstReader == current) {
                    // assert firstReaderHoldCount > 0;
                    //如果第一个读取器持有的读锁数量为1,则将第一个读取器设置为null,否则将其持有锁的数量自减
                    if (firstReaderHoldCount == 1)
                        firstReader = null;
                    else
                        firstReaderHoldCount--;
                 //如果第一读取器不是当前线程       
                } else {
                   //最后一个成功获取读锁的计数器
                    HoldCounter rh = cachedHoldCounter;
                    //如果计数器为null或最后一个成功获取读锁的不是当前线程
                    if (rh == null || rh.tid != getThreadId(current))
                        //将当前线程的计数器赋值给rh
                        rh = readHolds.get();
                     //当前线程持有读锁的数量   
                    int count = rh.count;
                    //如果持有锁的数量小于或等于1则将该线程从readHolds中删除
                    if (count <= 1) {
                        readHolds.remove();
                        //如果小于或等于0抛出异常,因为至少持有一把读锁
                        if (count <= 0)
                            throw unmatchedUnlockException();
                    }
                    //如果持有多把读锁则,持有锁的数量自减
                    --rh.count;
                }
    
                for (;;) {
                   //获取同步状态
                    int c = getState();
                    //计算释放一个读锁后读锁的数量
                    int nextc = c - SHARED_UNIT;
                    //CAS更新
                    if (compareAndSetState(c, nextc))
                        //如果本次释放后,读锁没有被占用则返回成功,否则返回失败
                        return nextc == 0;
                }
            }          
      writeLock.lock()
    public void lock() {
                sync.acquire(1);
            }
    
    public final void acquire(int arg) {
            if (!tryAcquire(arg) &&
                acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
                selfInterrupt();
        }        
    
     /*
      *尝试获取写锁,
      * 如果读锁占用数量不为0或写锁占用数量不为0且不是当前线程拥有写锁,则获取写锁失败
      * 如果写锁饱和同样失败
      * 否则当前线程具有获取锁的资格
      */
    protected final boolean tryAcquire(int acquires) {
                 //当前线程
                Thread current = Thread.currentThread();
                //获取同步状态
                int c = getState();
                //计算写锁数量
                int w = exclusiveCount(c);
                //如果有锁被占用(读锁或写锁)
                if (c != 0) {
                     //如果写锁没有被占用,则表示当前有读锁被占用,获取写锁失败;如果写锁被占用且不是当前线程占用则 当前线程获取写锁失败
                    if (w == 0 || current != getExclusiveOwnerThread())
                        return false;
                     //如果已经占有的写锁数量加上本次占用的和超过上限则抛出异常   
                    if (w + exclusiveCount(acquires) > MAX_COUNT)
                        throw new Error("Maximum lock count exceeded");
                    //写锁是当前线程占有,重入则将占用写锁的数量加上本次占用数量
                    setState(c + acquires);
                    //返回成功
                    return true;
                }
                //如果c==0表示读锁,写锁都没有被占用,判断写锁是否需要挂起,如果需要则返回获取锁失败,如果不需要则CAS竞争锁,失败返回false
                if (writerShouldBlock() ||
                    !compareAndSetState(c, c + acquires))
                    return false;
                 //不需要挂起且竞争到了写锁则将独占锁的拥有者设置为当前线程   
                setExclusiveOwnerThread(current);
                
                return true;
            }    
    writeLock.unlock()
      public void unlock() {
                sync.release(1);
            }
    
        public final boolean release(int arg) {
            if (tryRelease(arg)) {
                Node h = head;
                if (h != null && h.waitStatus != 0)
                    unparkSuccessor(h);
                return true;
            }
            return false;
        } 
        
        protected final boolean tryRelease(int releases) {
              //如果当前线程没有持有写锁则抛出异常
                if (!isHeldExclusively())
                    throw new IllegalMonitorStateException();
                 //计算释放写锁后的状态   
                int nextc = getState() - releases;
                //如果释放当前写锁后再无写锁占用,则free=true表示写锁完全释放,如果还有占用则free=false
                boolean free = exclusiveCount(nextc) == 0;
                //如果是完全释放则将当前线程设置为null
                if (free)
                    setExclusiveOwnerThread(null);
                 //更新同步状态   
                setState(nextc);
                return free;
            }  
        //判断当前占有写锁的线程是否是当前线程,如果是返回true,否则返回false    
        protected final boolean isHeldExclusively() {
                return getExclusiveOwnerThread() == Thread.currentThread();
            }       
     
     
     
     
     
  • 相关阅读:
    剑指offer之 二维数组的查找
    常用的基础算法总结之 希尔排序
    让shell脚本中的echo输出带颜色
    nginx利用lua实现nginx反向代理proxy_store缓存文件自删除
    LNMP平滑升级nginx并安装ngx_lua模块教程
    nginx的luajit安装luarocks并安装luafilesystem
    PHP图片识别成文字
    使用tesseract-ocr破解网站验证码
    利用开源程序(ImageMagick+tesseract-ocr)实现图像验证码识别
    http://ocr.wdku.net/
  • 原文地址:https://www.cnblogs.com/wei-zw/p/8797727.html
Copyright © 2020-2023  润新知