Java---ReentrantReadWriteLock---源码分析

ReentrantReadWriteLock

在ReentrantReadWriteLock中维护了两个锁,一个读锁,一个写锁。它的特性是。读锁在同一时刻允许多个线程访问。但是在写锁被访问时,所有访问读锁的线程和其它访问写锁的线程都会被阻塞。

在读多于写的情况下,读写锁能够提供比排他锁更好的并发性和吞吐量。

ReadLock

readLock:时序图

readLock:源码分析

tryAcquiredShared(int unused)

protected final int tryAcquireShared(int unused) {
	Thread current = Thread.currentThread();
    //  c为锁的状态位,高16位表示共享锁的数量,低16位表示独占锁的数量
	int c = getState();
    //  exclusiveCount(c) 取低16位的值,也就是写锁状态位:不等于0表示写锁被占用
    //  getExclusiveOwnerThread() != current  判断拥有锁的线程是不是当前线程
	if (exclusiveCount(c) != 0 &&
		getExclusiveOwnerThread() != current)
    //  返回 -1  表示获取锁失败
		return -1;
    //  获取高16位的值,即读锁的状态位
	int r = sharedCount(c);
    //  readerShouldBlock  ---见下文
    //  r < MAX_COUNT 判断读锁数量是否超过系统默认值
    //  compareAndSetState  cas修改高16位的读锁状态,即获取读锁
	if (!readerShouldBlock() &&
		r < MAX_COUNT &&
		compareAndSetState(c, c + SHARED_UNIT)) {
    //  首次获取读锁
		if (r == 0) {
    //  缓存首次获取读锁的线程以及重入次数
			firstReader = current;
			firstReaderHoldCount = 1;
		} else if (firstReader == current) {
			firstReaderHoldCount++;
		} else {
    //  cachedHoldCounter---最后获取锁的线程的读锁重入次数
			HoldCounter rh = cachedHoldCounter;
    //  readHolds是缓存了当前线程的读锁重入次数的ThreadLocal
    //  当前线程自然是最后获取锁的线程,故将当前线程的holdCounter赋给cachedHoldCounter
			if (rh == null || rh.tid != getThreadId(current))
				cachedHoldCounter = rh = readHolds.get();
			else if (rh.count == 0)
    //  缓存当前线程的holdCounter
    //  fullTryAcquireShared()方法中,
    //  获取读锁失败的线程会执行:readHolds.remove(),故此时需要重新设置 
				readHolds.set(rh);
			rh.count++;
		}
		return 1;
	}
    // step two : 获取读锁失败后,重新获取
	return fullTryAcquireShared(current);
}

fullTryAcquireShared(current);

final int fullTryAcquireShared(Thread current) {
    //  rh : 当前线程的锁计数器
            HoldCounter rh = null;
            for (;;) {
                int c = getState();
                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 {
                        if (rh == null) {
                            rh = cachedHoldCounter;
                            if (rh == null || rh.tid != getThreadId(current)) {
                                rh = readHolds.get();
                                if (rh.count == 0)
    //  线程阻塞之前,清空readHolds
                                    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;
                }
            }
        }

readerShouldBlock

FairSync
final boolean readerShouldBlock() {
    //  当前线程不是同步队列头结点的next节点(head.next) --阻塞当前线程 
    return hasQueuedPredecessors();
}

NonFairSync
final boolean readerShouldBlock() {    
    //  同步队列中的第一个线程若是以独占模式获取锁(写锁)-即获取写锁
    //  那么当前获取读锁的线程需要阻塞,让队列中的第一个线程先执行     
    return apparentlyFirstQueuedIsExclusive();
}

WriteLock

writeLock时序图

writeLock源码分析

tryAcquire

protected final boolean tryAcquire(int acquires) {
            Thread current = Thread.currentThread();
            int c = getState();
            int w = exclusiveCount(c);
            if (c != 0) {
                // (Note: if c != 0 and w == 0 then shared count != 0)
    //  拥有读锁或写锁的线程数非零并且当前线程并非锁拥有着,获取锁失败
                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;
            }
    //  c=0 当前无线程获得写锁
    //  writerShouldBlock()---判断是否符合  公平锁/非公平锁  策略
    //  compareAndSetState  cas尝试获得锁
            if (writerShouldBlock() ||
                !compareAndSetState(c, c + acquires))
                return false;
    //  写锁独占锁
            setExclusiveOwnerThread(current);
            return true;
        }

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值