JUC之ReentrantReadWriteLock

ReentrantReadWriteLock维护了一对相关的锁:共享锁readLock和独占锁writeLock。共享锁readLock用于读操作,能同时被多个线程获取;独占锁writeLock用于写入操作,只能被一个线程持有。

ReentrantReadWriteLock具有以下几种特性:

  • 公平性
    - 非公平模式
    默认模式。一个持续争用的非公平锁,可能会使其他读线程或写线程无限延期,但它比公平锁有更高的吞吐量。
    - 公平模式
    当构造一个公平锁时,线程争用使用一个近似顺序到达的策略。当目前持有的锁被释放,要么是等待时间最长的单个写入线程被分配写入锁,或者如果有一组读线程比所有等待写线程等待更长的时间,该组将被分配读取锁。
  • 重入性:
    ReentrantReadWriteLock允许读线程和写线程重复获取读锁或写锁。当所有写锁都被释放,不可重入读线程才允许获取锁。此外,一个写入线程可以获取读锁,但是一个读线程不能获取写锁。
  • 锁降级:
    重入性允许从写锁降级到读锁:首先获取写锁,然后获取读锁,然后释放写锁。不过,从一个读锁升级到写锁是不允许的。读锁和写锁在获取过程中都支持中断。
  • Condition支持:
    Condition只有在写锁中用到,读锁是不支持Condition的

Sync

 abstract static class Sync extends AbstractQueuedSynchronizer 
 {
        private static final long serialVersionUID = 6317671515068378041L;

        /*
         * Read vs write count extraction constants and functions.
         * Lock state is logically divided into two unsigned shorts:
         * The lower one representing the exclusive (writer) lock hold count,
         * and the upper the shared (reader) hold count.
         */
		// 最多支持65535(1<<16-1)个写锁和65535个读锁
		// 低16为表示写锁计数,高16为表示持有读锁的线程数
        static final int SHARED_SHIFT   = 16;
        //读锁高16位,读锁个数+1,其实是状态之+2^16
        static final int SHARED_UNIT    = (1 << SHARED_SHIFT);
        //锁最大数量(65535)
        static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;
        //写锁掩码,用于标记低16位
        static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;

        /** Returns the number of shared holds represented in count  
        *  读锁计数,当前持有读锁的线程数,c的高16位
        */
        static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }
        
        /** 
        * Returns the number of exclusive holds represented in count  
        * 写锁计数,也就是它的重入次数,c的低16位
        */
        static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }

        /**
         * A counter for per-thread read hold counts.
         * Maintained as a ThreadLocal; cached in cachedHoldCounter
         * 持有读锁的线程计数器
         */
        static final class HoldCounter 
        {
            //持有数
            int count = 0;
            // Use id, not reference, to avoid garbage retention
            final long tid = getThreadId(Thread.currentThread());
        }

        /**
         * ThreadLocal subclass. Easiest to explicitly define for sake
         * of deserialization mechanics.
         * 本地线程计数器
         */
        static final class ThreadLocalHoldCounter
            extends ThreadLocal<HoldCounter> 
        {
           //重写初始化方法,在没有进行set的情况下,获取的都是该HoldCounter的值
            public HoldCounter initialValue() 
            {
                return new HoldCounter();
            }
        }

        /**
         * The number of reentrant read locks held by current thread.
         * Initialized only in constructor and readObject.
         * Removed whenever a thread's read hold count drops to 0.
         */
        private transient ThreadLocalHoldCounter readHolds;

Sync类内部存在两个内部类,分别为HoldCounter和ThreadLocalHoldCounter,用来记录每个线程持有的读锁数量。

ReadLock

public static class ReadLock implements Lock, java.io.Serializable
{
    private static final long serialVersionUID = -5992448646407690164L;
    //持有的AQS对象
    private final ReentrantReadWriteLock.Sync sync;


    protected ReadLock(ReentrantReadWriteLock lock)
    {
        sync = lock.sync;
    }

    /**
     * 获取共享锁
     */
    public void lock()
    {
        sync.acquireShared(1);
    }

    /**
     * 获取共享锁(响应中断)
     * @throws InterruptedException
     */
    public void lockInterruptibly() throws InterruptedException
    {
        sync.acquireSharedInterruptibly(1);
    }

    /**
     * 尝试获取共享锁
     * @return
     */
    public boolean tryLock()
    {
        return sync.tryReadLock();
    }

    public boolean tryLock(long timeout, TimeUnit unit)
            throws InterruptedException
    {
        return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
    }

    /**
     * 释放锁
     */
    public void unlock()
    {
        sync.releaseShared(1);
    }

    /**
     * 新建条件
     * @return
     */
    public Condition newCondition()
    {
        throw new UnsupportedOperationException();
    }


    public String toString()
    {
        int r = sync.getReadLockCount();
        return super.toString() +
                "[Read locks = " + r + "]";
    }
}

tryAcquireShared

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();
            //持有写锁的线程可以获取读锁,如果获取锁的线程不是current线程;则返回-1
            if (exclusiveCount(c) != 0 &&
                getExclusiveOwnerThread() != current)
                return -1;
            //获取读锁的数量
            int r = sharedCount(c);
            if (!readerShouldBlock() &&
                r < MAX_COUNT &&
                compareAndSetState(c, c + SHARED_UNIT)) {
                //首次获取读锁,初始化firstReader和firstReaderHoldCount
                if (r == 0) 
                {
                    firstReader = current;
                    firstReaderHoldCount = 1;
                }
                //当前线程是首个获取读锁的线程
                else if (firstReader == current) 
                {
                    firstReaderHoldCount++;
                } 
                else 
                {
                	//更新cachedHoldCounter
                    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);
        }
  1. 如果“写锁”已经被持有,这时候可以继续获取读锁,但如果持有写锁的线程不是当前线程,直接返回-1(表示获取失败);

  2. 如果在尝试获取锁时不需要阻塞等待(由公平性决定),并且读锁的共享计数小于最大数量MAX_COUNT,则直接通过CAS函数更新读取锁的共享计数,最后将当前线程获取读锁的次数+1。

  3. 如果第二步执行失败,则调用fullTryAcquireShared尝试获取读锁,源码如下:

		/**
         * Full version of acquire for reads, that handles CAS misses
         * and reentrant reads not dealt with in tryAcquireShared.
         */
        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();
                //持有写锁的线程可以获取读锁
                if (exclusiveCount(c) != 0) 
                {
	                //如果获取锁的线程不是current线程,失败
                    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 
                    {
                    	//更新锁计数器
                        if (rh == null) 
                        {
                            rh = cachedHoldCounter;
                            if (rh == null || rh.tid != getThreadId(current)) 
                            {
                                rh = readHolds.get();
                                if (rh.count == 0)
                                	//当前线程持有读锁数为0,移除计数器
                                    readHolds.remove();
                            }
                        }
                        if (rh.count == 0)
                            return -1;
                    }
                }
                //超出最大读锁数量
                if (sharedCount(c) == MAX_COUNT)
                    throw new Error("Maximum lock count exceeded");
                //CAS更新读锁数量
                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;
                }
            }
        }

tryReleaseShared

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;
            }
        }

Note:在releaseShared中,首先调用tryReleaseShared尝试释放锁,方法流程很简单,主要包括两步:
更新当前线程计数器的锁计数;
CAS更新释放锁之后的state,这里使用了自旋,在state争用的时候保证了CAS的成功执行。

发布了306 篇原创文章 · 获赞 46 · 访问量 29万+

猜你喜欢

转载自blog.csdn.net/kaikai_sk/article/details/88702654
今日推荐