浅谈JAVA之读写锁ReentrantReadWriteLock

ReentrantReadWriteLock的锁策略有两种,分为公平策略和非公平策略,两者有些小区别,为便于理解,本小节将以示例的形式来说明多线程下,使用公平策略的读写锁是如何处理的。

其中读锁是共享锁,写锁是排他锁。只要存在写锁,临界区资源互斥。

锁降级:写锁换读锁。


可以看出ReentrantReadWriteLock拥有写锁WriteLock和ReadLock内部类,同时也拥有Sync内部类,实现了公平锁和非公平锁实现类,Sync又继承与AQS组件。

公平读写锁:

拥有写锁的线程能同时拥有读锁,即当线程拥有写锁的同时请求读锁,该临界区依然互斥。即临界区同时出现写锁和读锁。

即使拥有写锁的线程释放写锁唤醒了后继在等待队列需要读锁的线程,若后继线程没有重入读锁,临界区依然互斥。即出现临界区只有读锁但无法重入的状况。

首先看一下即将出场的伙伴们,我们一共会出场几个线程,还有用于实现读写机制的AQS同步器队列。每个线程中的 R(0)W(0)表示当前线程占用了多少读写锁。

1.线程A请求一个读锁,此时无人竞争锁,A获取读锁1,即线程A重入次数为1,如下所示:

这里写图片描述

2.线程B请求一个读锁,由于AQS中没有等待节点,当前处于读锁占有状态(线程A占有1个读锁),所以B成功获取读锁,如下所示:

这里写图片描述

3.这时候,线程C请求一个写锁,由于当前其他两个线程拥有读锁,写锁获取失败,线程C入队列,如下所示:

这里写图片描述

AQS初始化会创建一个空的头节点,C入队列,然后会休眠,等待其他线程释放锁唤醒。

4.线程D也来了,线程D想获取一个读锁,虽然当于处于读锁占有阶段,但是目前D不占有任何数量的读锁,而且同步器队列中已经有等待节点,这时候,由于公平策略,D不得已,一个字,等,如下图所示:

这里写图片描述

5.这时候,线程A执行完了,释放了读锁,由于B仍然占有读锁,所以释放后读锁仍然没有完全释放,写锁仍然没有机会执行,如下图所示:

这里写图片描述

6.这次,B也执行完了,执行完后,读锁全部释放,这时候会唤醒排在同步器队头的节点C,C成功获取一个写锁,如下图所示:

这里写图片描述

7.一旦任何一个线程获取了写锁,除了该线程自己,其它线程都将无法获取读锁和写锁,这时候,线程C再次请求一个读锁,这是允许的,但反过来如果一个线程先获取了读锁,再获取写法则是不行的。这时候的状态如下图所示:

这里写图片描述

8.这时候假设线程E也来了,E想获取读锁,由于当前处于写锁状态,直接入队,如下所示:

这里写图片描述

9.这会C终于把活干完了,把读锁和写锁都给释放了,然后线程D被唤醒,获取了读锁,如下图所示:

这里写图片描述

10.这时候,如果再来一个线程,比如A,也想获取读锁,由于节点中还有线程E在等待,而且当前线程A没有获取任何读锁,不是重入状态,所以只能置入队尾,如下图所示:

这里写图片描述

11.这时候,如果D再次调用了一次获取读锁,由于D属于可重入状态,所以直接把读锁+1即可,如下图所示:

这里写图片描述

12.由于D获取的是读锁,同步队列中的E等待的也是读锁,所以E会被唤醒,获取读锁继续执行,如下图所示:

这里写图片描述

13.同样的,由于线程A获取的是读锁,在E执行后,会唤醒线程A,A也可以获得读锁,并继续执行,如下图所示:

这里写图片描述

14.最后大家各自执行,悄然退场。


非公平读写锁:

区别:在写锁释放后,等待队列中的读锁请求会通过CAS操作进行重入竞争。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值