java锁(2)ReentrantReadWriteLock

ReentrantReadWriteLock

1.        特点:ReentrantReadWriteLock是一个读写锁,它提供了一个读锁和一个写锁,读锁用于只读操作,而写锁用于写入操作,读操作可以并行进行,而写操作则是互斥的。读锁和写锁的分离在一些写少读多的应用中可以带来性能上的提升

2.        读锁与写锁的约束关系

1)        当任一线程持有写锁或读锁时,其他线程不能获得写锁;

2)        当任一线程持有写锁时,其他线程不能获取读锁;

3)        多个线程可以同时持有读锁。

3.        优点:实现并发的读和互斥的写,达到很多操作并行的目地,从而提高性能。

4.        使用:

1)        创建一个读锁和一个写锁


2)        通过读锁实现并发读


3)        通过写锁实现互斥写


锁的获取顺序

1.        非公平模式:

1)        非公平模式不按照线程请求锁的顺序分配锁,而是当前请求锁的线程和等待队列中的线程一起竞争锁。

2)        连续竞争的非公平锁可能会导致等待队列中的线程长时间等待,但吞吐量要高于公平锁。

3)        非公平模式中,如果等待队列的头节点是写者线程(当前执行的可能是一个写者线程或者是多个读者线程),那么新到的读者线程将进入等待队列中阻塞。

4)        队头的写者线程,在当前正在执行的一个写者线程或者多个读者线程执行完成后,就会得到执行(如果存在新到写者线程,则需要竞争),防止等待队列中的写者线程一直等待。

2.        公平模式:

1)        公平模式采用近似FIFO的策略获取锁

2)        当一个线程释放了锁后,等待队列中等待时间最长的线程(单个写线程或者多个读线程)将获取锁(写锁或者读锁)。

3)        由于公平模式采用FIFO的策略获取锁,因此不存在写线程一直等待的问题。

重入

允许写者和读者按照ReentrantLock的方式多次获取读锁或写锁

1.        获取写锁的线程可以再次获取读锁:即写锁可以降级为读锁

2.        获取读锁的线程不能再次获取写锁:即读锁不可以升级为写锁

Condition支持

1.        读锁不支持Condition:readLock().newCondition()会抛出Unsupported OperationException

2.        写锁支持Condition:对于写入锁来说,该实现的行为与 ReentrantLock.newCondition()提供的Condition 实现对ReentrantLock所做的行为相同

ReentrantReadWriteLock的实现

1.        同步状态


1)        ReentrantReadWriteLock是将AQS中同步状态的整型变量分为了两个部分来实现的

Ø  低位的16位用于保存写锁状态;

Ø  高位的16位用于保存读锁状态;

2)        sharedCount:用于获取共享锁(读锁)数量,因为读锁是共享锁;

3)        exclusiveCount:用于获取排它锁(写锁)数量,因为写锁是排它锁。

2.        读锁与写锁

1)        读锁


a)        Lock():调用的是AQS中的acquireShared方法。

b)        Unlock():调用的是AQS中的releaseShared方法。

c)        采用的是AQS的共享模式,且不支持newCondition操作

2)        写锁


a)        Lock():调用AQS的acquire方法;

b)        Release():调用AQS的忍了阿萨我方法;

c)        写锁采用的是AQS的排它模式,且支持newCondition 操作;

3.        非公平模式

1)        写锁:获取锁


1.        获取当前同步状态c

2.        通过同步状态C获取写锁的数量

3.        C!=0 表示所以被占用(可能是写锁,也可能是读锁)

4.        W=0 表当前占用的是读锁,返回false

Ø  若w!=0 表示当前占用的是写锁,需进一步判断,是否是自己占用了这个写锁。

Ø  若不是返回false

5.        检查是否超过锁的上限

6.        修改写锁数

7.        (写线程永不阻塞)C=0 表示当前没有锁被占用,故修改锁的状态、将锁的拥有者声明为自己。

2)        写锁:释放锁


a)        检测:判断是否是锁的拥有者

b)        修改锁的状态

c)        若锁为0,表示释放锁

d)        将锁的拥有者置为空

3)        读锁:获取锁


1.        第一步获得所得状态

2.        若已有排他锁(写锁)占用并且写锁拥有者不是当前线程,怎返回-1;

上面检查完后,至此说明当前占用的是读锁,读锁是可以并发的。

3.        获得共享锁的个数,即读锁的个数;

4.        由于读锁不应该让写锁始终等待,故需要判断是否应该阻塞。

5.        如果readerShouldBlock返回false,且读锁数量小于MAX_COUNT,就可以尝试将读锁数量修改到c + SHARED_UNIT

6.        如果上步骤4中的条件都通过了,就表示读锁获取成功了,接下来的操作就是设置计数信息了。

7.        如果步骤4中条件失败,表示获取读锁失败,阻塞并等待唤醒。

4.        公平模式

1)        写锁:与非公平锁类似,唯一的差异就在于在tryAcquire中对writerShouldBlock的判断:


hasQueuedPredecessors:用于判断等待队列中是否存在等待线程,如果存在等待线程,则厚道的线程将进入等待队列中阻塞等待。

2)        读锁:同上,在是否应阻塞的判断上不一样,也是唯一区别。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值