读写锁

读锁为共享锁,而写锁则为独占锁,同时他们用的是一个同步器,同步器中不同的内部类实现了相应的功能


在AQS章节中介绍到AQS中有一个state字段(int类型,32位)用来描述有多少线程获持有锁。在独占锁的时代这个值通常是0或者1(如果是重入的就是重入的次数),在共享锁的时代就是持有锁的数量。在上一节中谈到,ReadWriteLock的读、写锁是相关但是又不一致的,所以需要两个数来描述读锁(共享锁)和写锁(独占锁)的数量。显然现在一个state就不够用了。于是在ReentrantReadWrilteLock里面将这个字段一分为二,高位16位表示共享锁的数量,低位16位表示独占锁的数量(或者重入数量)。2^16-1=65536,这就是上节中提到的为什么共享锁和独占锁的数量最大只能是65535的原因了。

02104105_58fZ.jpg

1.在独占数量上则采用了return c & EXCLUSIVE_MASK  

EXCLUSIVE_MASK  = (1 << SHARED_SHIFT) - 1; 表示向左移动16位 然后减掉1,即低16位全为1,高16位全为0

即通过 & 000(....)111(....)的形式获取低16位

通过与操作就能知道states变量的低16的值,也即独占锁数量

2.共享锁数量上则采用了往右移16位的形式,最高位都补0,

即111111(...)变成了类似000111(...)的形式获取高16位


写锁的获取  02104105_gKXU.jpg

一、

    c!=0说明有锁了,

    1.w==0成立说明有多个读锁在用了,这时不能获取写锁,因为写锁将导致数据乱掉

    2.w!=0 成立 说明当前有写锁,如果该线程进来竞争写锁又不是当前线程的话则不行,他们是独占的,同时如果写锁进来后加起来超过了65535(即16位都为1的情况下再进来一个写锁的话)则报错,超出了能记录的锁数量限制


二、

    c==0说明没有任何的锁,

02104105_EmCk.jpg

   前面判断写是不是需要阻塞(这个是公平锁和非公平锁的阻塞情况),

02104105_oZ6N.jpg

如果AQS队列不为空或者当前线程不在队列头部那么就阻塞队列(即加入到同步队列中自身不断自旋)

后面判断获取写锁,失败直接false,其他则true


写锁的释放

02104105_g7fM.jpg

判断是否存在重入的情况,如果是重入的话不能将当前的线程信息清空


读锁的获取

1.首先判断是否存在写锁 同时当前线程是否为那个线程,如果不是拜拜,如果是的话则到2(允许写锁的线程同时获取读锁)

2.读是否阻塞,读锁数量有没有超过,那么读锁就CAS +1,如果判断没通过自旋去吧


读锁释放

不断的自旋CAS


读锁里面存在一个特别的HoldCounter,因为读锁是共享的,存在多个读锁的情况,同时释放的时候其实是类似计数器的形式,为了避免一个线程操作了一个不属于自己监听器对象的异常,也就是一个线程释放了一个不属于自己的或不存在的共享锁就引入了HoldCounter

HoldCounter的作用后我们就可以猜到它的作用其实就是当前线程持有共享锁(读取锁)的数量,包括重入的数量。那么这个数量就必须和线程绑定在一起,表示线程持有读取锁数量的计数器。可以看到这里使用ThreadLocal将HoldCounter绑定到当前线程上,同时HoldCounter也持有线程Id,这样在释放锁的时候才能知道ReadWriteLock里面缓存的上一个读取线程(cachedHoldCounter)是否是当前线程。这样做的好处是可以减少ThreadLocal.get()的次数,因为这也是一个耗时操作。需要说明的是这样HoldCounter绑定线程id而不绑定线程对象的原因是避免HoldCounter和ThreadLocal互相绑定而GC难以释放它们(尽管GC能够智能的发现这种引用而回收它们,但是这需要一定的代价),所以其实这样做只是为了帮助GC快速回收对象而已。

02104105_EIZ8.jpg


转载于:https://my.oschina.net/u/2337927/blog/538188

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值