ReentrantReadWriteLock获取写锁和锁降级

      由于在 AbstractQueuedSynchronizer中用 int state 表示锁状态, ReentrantReadWriteLock要在一个变量上维护读和写2个锁状态, ReentrantReadWriteLock把state 切分为2个部分,高16位表示读,低16位表示写,即
 
0000000000000000      0000000000000000
高16位读状态                低16位写状态
 
       同步状态通过位运算维护状态,假设当前同步状态为S,写状态等于S & 0x0000FFFF (低16位全为1,高16位全抹去),读状态等于S>>>16(无符号补零右移16位)
在 ReentrantReadWriteLock源码中:
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;

/** Returns the number of shared holds represented in count */
static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
/** Returns the number of exclusive holds represented in count */
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
 
  
0x0000FFFF 对应EXCLUSIVE_MASK, sharedCount(int c) 返回当前读状态,exclusiveCount返回当前写状态,和上面的计算方法一样。由此得出: S不等于0时,当写状态(S & 0x0000FFFF)等于0时,读状态(S>>>16)大于0,即读锁已被读取。
1   写锁的获取
ReentrantReadWriteLock.WriteLock的lock()方法:
public void lock() {
sync.acquire(1);
}
       调用内部Sync.acquire(int arg),即AbstractQueuedSynchronizer中的acquire(int  arg),之前已经对该方法分析过,该方法为模板方法,独占式获取锁,内部调用子类(ReentrantReadWriteLock.Sync)的tryAcquire(int arg):
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);
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;
}
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
return false;
setExclusiveOwnerThread(current);
return true;
}
该方法先获取同步状态c和写状态w。
(1)当c!=0 并且w = 0时 表示当前读锁被读取,以及当前线程不是获取写锁的线程时,则不能获取写锁。原因在于:读写锁要确保写锁的操作对读锁课件,如果允许读锁在已被获取的情况下获取写锁,那么正在运行的其他读线程就无法感知到写线程的操作。因此,只有等待其他读线程都释放了读锁,写锁才能被当前线程获取,一旦写锁被获取,其他读写线程的后续访问均被阻塞。
(2)当前线程为已获取写锁的线程时,更新state,返回成功。
(3)当c=0时,表示没有读写锁和写锁,获取写锁。
 
2 锁降级
       锁降级是指写锁降级为读锁。如果当前线程拥有写锁,然后将其释放,最后再获取读锁,这种分段完成的过程不叫锁降级。锁降级是指把持住(当前拥有)写锁,再获取到读锁,然后释放(先前拥有的)写锁的过程。锁降级中读锁的获取是否有必要呢?答案是必要的。主要是为了保证数据的可见性,如果当前线程不获取读锁而是直接释放写锁,假设此刻另一个线程T获取了写锁了并修改了数据,那么当前线程无法感知到线程T的数据更新。如果当前线程获取读锁,即遵循锁降级的步骤,则线程T将会被阻塞,直到当前线程使用数据并释放读锁之后,线程T才能获取写锁进行数据更新。
ReentrantReadWriteLock并不支持锁升级(把持读锁,获取写锁,最后释放读锁的过程)。目的也是保证数据可见性。如果读锁已经被多个线程获取,其中任意线程成功获取了写锁并更新了数据,则其更新数其他获取到读锁的线程是不可见的。
 
 
 
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值