从ReentrantReadWriteLock看AQS

大家推荐个靠谱的公众号程序员探索之路,公众号内点击网赚获取彩蛋,大家一起加油,这个公众号已经接入图灵https://img-blog.csdnimg.cn/20181129224604602.png ​  

======================================
1.ReentrantReadWriteLock属性和读/写锁 概要
======================================
/** Inner class providing readlock */
    private final ReentrantReadWriteLock.ReadLock readerLock;
    /** Inner class providing writelock */
    private final ReentrantReadWriteLock.WriteLock writerLock;
    /** Performs all synchronization mechanics */
    final Sync sync;
    
    /**
     * 读锁
     */
    public static class ReadLock implements Lock, java.io.Serializable {
        private static final long serialVersionUID = -5992448646407690164L;
        private final Sync sync;

        /**
         * Constructor for use by subclasses
         *
         * @param lock the outer lock object
         * @throws NullPointerException if the lock is null
         */
        protected ReadLock(ReentrantReadWriteLock lock) {
            sync = lock.sync;
        }

        /**
         * Acquires the read lock.
         *
         * <p>Acquires the read lock if the write lock is not held by
         * another thread and returns immediately.
         *
         * <p>If the write lock is held by another thread then
         * the current thread becomes disabled for thread scheduling
         * purposes and lies dormant until the read lock has been acquired.
         */
        public void lock() {
            sync.acquireShared(1);
        }
        .....
    
    /**
     * 写锁
     */
    public static class WriteLock implements Lock, java.io.Serializable {
        private static final long serialVersionUID = -4992448646407690164L;
        private final Sync sync;

        /**
         * Constructor for use by subclasses
         *
         * @param lock the outer lock object
         * @throws NullPointerException if the lock is null
         */
        protected WriteLock(ReentrantReadWriteLock lock) {
            sync = lock.sync;
        }

        /**
         * Acquires the write lock.
         *
         * <p>Acquires the write lock if neither the read nor write lock
         * are held by another thread
         * and returns immediately, setting the write lock hold count to
         * one.
         *
         * <p>If the current thread already holds the write 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 write lock has been acquired, at which
         * time the write lock hold count is set to one.
         */
        public void lock() {
            sync.acquire(1);
        }
    ......
        没什么注释,因为没什么好说的这块
================================
2.ReentrantReadWriteLock里的sync
================================
    abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 6317671515068378041L;

        /*
         读写锁将锁状态state 高16位用于共享模式 低16位用于独占模式
         */

        static final int SHARED_SHIFT   = 16;
        static final int SHARED_UNIT    = (1 << SHARED_SHIFT);
        static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;
        static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;

        /**
        取高16位的值  代表读锁的获取次数(包括重入)
        */
        static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }
        /**
        取低16位的值 代表写锁的重入次数  ???为什么不是获取次数 写锁是独占模式拉
        */
        static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }

        /**
         * 这个类的实例 代表的是线程持有的读锁的数量
         */
        static final class HoldCounter {
            int count = 0;
            // 或者线程的id
            final long tid = getThreadId(Thread.currentThread());
        }

        /**
       
         */
        static final class ThreadLocalHoldCounter
            extends ThreadLocal<HoldCounter> {
            public HoldCounter initialValue() {
                return new HoldCounter();
            }
        }

        /**
         记录当前线程的读锁重入次数
         */
        private transient ThreadLocalHoldCounter readHolds;

        /**
         用于缓存,记录最后一个获取读锁的线程的重入次数
         */
        private transient HoldCounter cachedHoldCounter;

        /**
        第一个获取读锁的线程(并且未释放读锁),以及它持有的读锁数量
         */
        private transient Thread firstReader = null;
        private transient int firstReaderHoldCount;

        Sync() {
            readHolds = new ThreadLocalHoldCounter();
            setState(getState()); // ensures visibility of readHolds
        }
        
==================
3.读锁的lock/unlock
==================
        public void lock() {
            sync.acquireShared(1);
        }
        
    public final void acquireShared(int arg) {
        //如果 < 0代表没有获取锁
        if (tryAcquireShared(arg) < 0)
            //没有获取锁进入等待队列
            doAcquireShared(arg);
    }
    protected final int tryAcquireShared(int unused) {
            /*
             * Walkthrough:
             * 1. If write lock held by another thread, fail.
             * 2. Otherwise, this thread is eligible for
             *    lock wrt state, so ask if it should block
             *    because of queue policy. If not, try
             *    to grant by CASing state and updating count.
             *    Note that step does not check for reentrant
             *    acquires, which is postponed to full version
             *    to avoid having to check hold count in
             *    the more typical non-reentrant case.
             * 3. If step 2 fails either because thread
             *    apparently not eligible or CAS fails or count
             *    saturated, chain to version with full retry loop.
             */
            Thread current = Thread.currentThread();
            int c = getState();
            //如果有 写锁 并且 当前占有锁的线程不是 本线程  返回-1 那么返回到外层就是进入等待队列  注意这里的条件 有写锁而且有锁的不是本线程返回-1
            //也就是说 如果有写锁 但是获取写锁的线程是本线程 是可以获取读锁的  这中操作叫做锁降级  相反不能锁升级 
            //我猜的锁降级的作用是提升性能 因为本线程对内容的修改(也就是写操作)在自己的线程栈中是可见的 所以也能获取读锁
            if (exclusiveCount(c) != 0 &&
                getExclusiveOwnerThread() != current)
                return -1;
            //获取读锁(也就是共享锁)的数量
            int r = sharedCount(c);
            //允许获取锁 并且 锁的总数量 < 最大锁数量 并且 将 state 属性的高 16 位加 1,低 16 位不变  如果成功就代表获取到了读锁
            if (!readerShouldBlock() &&
                r < MAX_COUNT &&
                compareAndSetState(c, c + SHARED_UNIT)) {
                //下面都是未获取锁的
                
                //如果r == 0表示 在此获取之前没有线程获取过读锁  设置第一个获取读锁的线程
                if (r == 0) {
                    firstReader = current;
                    firstReaderHoldCount = 1;
                //如果是第一个获取读锁的重入
                } else if (firstReader == current) {
                    firstReaderHoldCount++;
                } else {
                    //这个分支是 更新缓存获取最后一个读锁的线程  
                    HoldCounter rh = cachedHoldCounter;
                    //更新最后
                    if (rh == null || rh.tid != getThreadId(current))
                        cachedHoldCounter = rh = readHolds.get();
                    else if (rh.count == 0)
                        readHolds.set(rh);
                    rh.count++;
                }
                return 1;
            }
            return fullTryAcquireShared(current);
        }
        
        /**
         * 这个方法的目的是 上面先判断没有线程占有写锁 但是读线程获取锁失败 这里表示不服 需要重新试一次
         */
        final int fullTryAcquireShared(Thread current) {
            /*
             * This code is in part redundant with that in
             * tryAcquireShared but is simpler overall by not
             * complicating tryAcquireShared with interactions between
             * retries and lazily reading hold counts.
             */
            HoldCounter rh = null;
            //注意这是一个循环
            for (;;) {
                int c = getState();
                //和之前的判断一样如果有 写锁 并且 当前占有锁的线程不是 本线程  返回-1 那么返回到外层就是进入等待队列
                if (exclusiveCount(c) != 0) {
                    if (getExclusiveOwnerThread() != current)
                        return -1;
                    // else we hold the exclusive lock; blocking here
                    // would cause deadlock.
                } else if (readerShouldBlock()) {
                    //走到这块里面表示 可以阻塞读锁 下面的做到判断是 重入的处理
                    // Make sure we're not acquiring read lock reentrantly
                    if (firstReader == current) {
                        // assert firstReaderHoldCount > 0;
                    } else {
                        //这里发现 缓存的本线程的读锁获取次数为0 那么就是初始化的值 所以不好意思 你不是重入乖乖等待
                        if (rh == null) {
                            rh = cachedHoldCounter;
                            if (rh == null || rh.tid != getThreadId(current)) {
                                rh = readHolds.get();
                                if (rh.count == 0)
                                    readHolds.remove();
                            }
                        }
                        if (rh.count == 0)
                            return -1;
                    }
                }
                //重入锁的最大数量判断
                if (sharedCount(c) == MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
                //尝试获取锁
                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;
                }
            }
        }
        /**
        判断读锁是否应该阻塞 true 是 false 不是
        公平模式下 队列中有元素就排对  重入除外
        非公平模式下 如果是重入那么不等待    如果不是重入且head.next是写锁那么等待  如果不是重入而且head.next不是写锁那么大家公平竞争比cas速度 
        */
        final boolean readerShouldBlock() {
            return hasQueuedPredecessors();
        }
        /**
        公平模式
        */
        public final boolean hasQueuedPredecessors() {
            // The correctness of this depends on head being initialized
            // before tail and on head.next being accurate if the current
            // thread is first in queue.
            Node t = tail; // Read fields in reverse initialization order
            Node h = head;
            Node s;
            return h != t &&
                ((s = h.next) == null || s.thread != Thread.currentThread());
        }
    /**
     * Nonfair version of Sync 非公平模式
     */
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = -8159625535654395037L;
        final boolean writerShouldBlock() {
            return false; // writers can always barge
        }
        final boolean readerShouldBlock() {
            /* As a heuristic to avoid indefinite writer starvation,
             * block if the thread that momentarily appears to be head
             * of queue, if one exists, is a waiting writer.  This is
             * only a probabilistic effect since a new reader will not
             * block if there is a waiting writer behind other enabled
             * readers that have not yet drained from the queue.
             */
            return apparentlyFirstQueuedIsExclusive();
        }
    }
     /**
     * Acquires in shared uninterruptible mode.
     * @param arg the acquire argument
     这个和之前分析的aqs 一样 都是 在等待队列中等待
     */
    private void doAcquireShared(int arg) {
        final Node node = addWaiter(Node.SHARED);
        boolean failed = true;
        try {
            boolean interrupted = false;
            for (;;) {
                final Node p = node.predecessor();
                if (p == head) {
                    int r = tryAcquireShared(arg);
                    if (r >= 0) {
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        if (interrupted)
                            selfInterrupt();
                        failed = false;
                        return;
                    }
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }
    
    ------------释放锁
    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;
                if (firstReaderHoldCount == 1)
                    firstReader = null;
                else
                    firstReaderHoldCount--;
            } else {
                //如果当前线程刚好是 最后一个,如果不是获取该线程获取锁的次数
                HoldCounter rh = cachedHoldCounter;
                if (rh == null || rh.tid != getThreadId(current))
                    rh = readHolds.get();
                int count = rh.count;
                //锁获取次数修改
                if (count <= 1) {
                    readHolds.remove();
                    if (count <= 0)
                        throw unmatchedUnlockException();
                }
                --rh.count;
            }
            //循环设置读锁状态
            for (;;) {
                int c = getState();
                int nextc = c - SHARED_UNIT;
                if (compareAndSetState(c, nextc))
                    // Releasing the read lock has no effect on readers,
                    // but it may allow waiting writers to proceed if
                    // both read and write locks are now free.
                    return nextc == 0;
            }
    }
    
    /**
    这个就是真正唤醒的操作  和之前分析的aqs一样
    */
    private void doReleaseShared() {
        /*
         * Ensure that a release propagates, even if there are other
         * in-progress acquires/releases.  This proceeds in the usual
         * way of trying to unparkSuccessor of head if it needs
         * signal. But if it does not, status is set to PROPAGATE to
         * ensure that upon release, propagation continues.
         * Additionally, we must loop in case a new node is added
         * while we are doing this. Also, unlike other uses of
         * unparkSuccessor, we need to know if CAS to reset status
         * fails, if so rechecking.
         */
        for (;;) {
            Node h = head;
            if (h != null && h != tail) {
                int ws = h.waitStatus;
                if (ws == Node.SIGNAL) {
                    if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                        continue;            // loop to recheck cases
                    unparkSuccessor(h);
                }
                else if (ws == 0 &&
                         !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                    continue;                // loop on failed CAS
            }
            if (h == head)                   // loop if head changed
                break;
        }
    }
    
==================
4.写锁的lock/unlock
==================

        public void lock() {
            sync.acquire(1);
        }
    //看着是不是很熟悉 其实就是tryAcquire不一样 另外的点是一样的        
    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
    
    protected final boolean tryAcquire(int acquires) {
            /*
             * Walkthrough:
             * 1. If read count nonzero or write count nonzero
             *    and owner is a different thread, fail.
             * 2. If count would saturate, fail. (This can only
             *    happen if count is already nonzero.)
             * 3. Otherwise, this thread is eligible for lock if
             *    it is either a reentrant acquire or
             *    queue policy allows it. If so, update state
             *    and set owner.
             */
            Thread current = Thread.currentThread();
            int c = getState();
            //获取写锁状态
            int w = exclusiveCount(c);
            //c != 0 表示有可能有线程占用了锁 但是得具体看看
            if (c != 0) {
                // 看下这里返回 false 的情况:
                //   c != 0 && w == 0: 写锁可用,但是有线程持有读锁(也可能是自己持有)
                //   c != 0 && w !=0 && current != getExclusiveOwnerThread(): 其他线程持有写锁
                //   也就是说,只要有读锁或写锁被占用,这次就不能获取到写锁
                if (w == 0 || current != getExclusiveOwnerThread())
                    return false;
                if (w + exclusiveCount(acquires) > MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
                // Reentrant acquire
                setState(c + acquires);
                //一路走来成功了 就是获取了
                return true;
            }
            //如果不能获取写锁 或者cas  state失败 返回false
            if (writerShouldBlock() ||
                !compareAndSetState(c, c + acquires))
                return false;
            //设置获取锁的线程
            setExclusiveOwnerThread(current);
            return true;
        }
        
static final class NonfairSync extends Sync {
    // 如果是非公平模式,那么 lock 的时候就可以直接用 CAS 去抢锁,抢不到再排队
    final boolean writerShouldBlock() {
        return false; // writers can always barge
    }
}
static final class FairSync extends Sync {
    final boolean writerShouldBlock() {
        // 如果是公平模式,那么如果阻塞队列有线程等待的话,就乖乖去排队
        return hasQueuedPredecessors();
    }
}
 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值