Java JUC包下ReentrantReadWriteLock读写计数器合并的原因分析

Java JUC包下ReentrantReadWriteLock读写计数器合并为一个原理解析@TOC

通过阅读java鼻祖 Doug Lea 的并发编程中读写锁的使用原理,对于ReentrantReadWriteLock使用的Sync实现方法进行研究,同时也为了加深映像,自己实现了简单的读写锁。对于ReentrantReadWriteLock.Sync的State这个值的设计确实巧妙。
State值记录了读写锁的计数器,使用的是int类型,分为两段,前面16位记录的是当前读加锁的计数,后面16位记录的时候当前写加锁的计数,在Sync类中有计算读写锁计数的位运算。

/*
* 读/写 计数换算的常量和方法。
* 锁状态是分为两个无符号的短整型:
* 低位的代表互斥锁(写锁)持有的数量,
* 高位代表共享锁(读锁)持有的数量
*/
//共享锁的位数
static final int SHARED_SHIFT   = 16; 
//共享锁每次递增的量 二进制的值为 0x0001 0000
static final int SHARED_UNIT    = (1 << SHARED_SHIFT);
//读写锁分别持有的最大数量 2^16 - 1
static final int MAX_COUNT      = (1 << SHARED_SHIFT) - 1;
//互斥锁(写锁)掩码 0x0000 FFFF
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
/** 返回共享锁的数量  */
static int sharedCount(int c)    { return c >>> SHARED_SHIFT; }
/** 返回互斥锁的数量  */
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }

那么问题来了,为什么在读写锁中要把读写计数器放在一个State的int值中?
先来看下获取写锁加锁的方法实现 具体实现是 sync.tryWriteLock();

/**
 * Performs tryLock for write, enabling barging in both modes.
 * This is identical in effect to tryAcquire except for lack
 * of calls to writerShouldBlock.
 */
final boolean tryWriteLock() {
    Thread current = Thread.currentThread();
    int c = getState();
    if (c != 0) {
        int w = exclusiveCount(c);
        if (w == 0 || current != getExclusiveOwnerThread())
            return false;
        if (w == MAX_COUNT)
            throw new Error("Maximum lock count exceeded");
    }
    if (!compareAndSetState(c, c + 1))
        return false;
    setExclusiveOwnerThread(current);
    return true;
}

重点的语句是 compareAndSetState(c, c + 1) 表示在进行写加锁的时候进行CAS操作,此时把读锁的Count值也计算在内,避免了线程异常,如果自己实现读写锁的时候,肯定会把读写锁的计数器分开,这样子在进行CAS操作的时候,需要再次加锁,增加系统开销。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值