并发编程之读写锁ReentrantReadWriteLock&StampLock详解

  现实中有这样一种场景:对共享资源有读和写的操作,且写操作没有读操作那么频繁(读多写少)。在没有写操作的时候,多个线程同时读一个资源没有任何问题(不存在线程安全问题),并且也应该允许多个线程同时读取共享资源(读读共享);但是,如果一个线程想去写这些共享资源,就不应该允许其他线程对该资源进行读和写操作了(读写,写写互斥),否则可能会出现线程安全问题。

思考:上述不管哪种情况,控制访问资源如果都通过ReentrantLock独占锁来解决,性能上会大打折扣,因为读读操作是不需要加锁的。针对这种场景,有没有比ReentrantLock更好的方案?那就是读写锁。

总结:读读不存在线程安全问题。写读、写写操作存在线程安全问题。

如何设计一把读写锁?(读读共享,写读、写写互斥)

利用AQS

互斥:tryAcquire、tryRelease     写锁   state=0  1

共享:tryAcquireShared、tryReleaseShared   读锁  state!=0

怎么保证读写互斥?

通过状态来判断。但是,这里有两个状态:读状态 、写状态

ReentrantReadWriteLock是基于AQS实现的,而AQS中只有一个state变量。如何通过一个变量控制两种状态?高地位

AQS中的state是int类型,在java中占四个字节

00000000 00000000 00000000 00000000  高16位 低16位。高16位控制读,低16位控制写

读写互斥,加写锁时怎么判断是否有读锁?

通过Java位运算实现

如果要实现可重入,怎么做?

对于写锁,因为是独占的,只会有一个线程占用写锁,所以,只允许占用写锁的线程重入,通过状态+1即可实现

对于读锁,允许多个线程重入,而通过state的高16位记录每个线程的重入次数是不现实的,高16位只能记录获取读锁的线程个数。那怎么办呢?可以通过ThreadLocal(线程私有的)来解决。

1. 读写锁介绍

  读写锁ReadWriteLock,顾名思义一把锁分为读和写两部分,读锁允许多个线程同时获得,因为读操作本身是线程安全的。而写锁是互斥锁,不允许多个线程同时获得写锁。并且,读和写操作也是互斥的。读写锁适合多读少写的业务场景。

2. ReentrantReadWriteLock

  针对这种场景, JAVA的并发包提供了读写锁ReentrantReadWriteLock ,它内部维护了一对相关的锁, 一个用于只读操作,称为读锁;一个用于写入操作,称为写锁 ,描述如下:

线程进入读锁的前提条件:

  • 没有其他线程的写锁;
  • 没有写请求或者有写请求,但调用线程和持有锁的线程是同一个;

线程进入写锁的前提条件:

  • 没有其他线程的读锁;
  • 没有其他线程的写锁;

而读写锁有以下三个重要的特性:

  • 公平选择性:支持非公平(默认)和公平的锁获取方式,吞吐量还是非公平优于公平;
  • 可重入:读锁和写锁都支持线程重入。以读写线程为例:读线程获取读锁后,能够再次获取读锁。写线程在获取写锁之后能够再次获取写锁,同时也可以获取读锁;
  • 锁降级:遵循获取写锁、再获取读锁最后释放写锁的次序,写锁能够降级成为读锁;

2.1. ReentrantReadWriteLock的使用

2.1.1. 读写锁接口ReadWriteLock

接口中有一对方法,分别是获得读锁和写锁 Lock 对象。

2.1.2. ReentrantReadWriteLock类结构

  ReentrantReadWriteLock是可重入的读写锁实现类。在它内部,维护了一对相关的锁,一个用于只读操作,另一个用于写入操作。只要没有 Writer 线程,读锁可以由多个 Reader 线程同时持有。也就是说,写锁是独占的,读锁是共享的。

2.1.3. 如何使用读写锁

1. 使用方式

private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();
private final Lock r = readWriteLock.readLock();
private final Lock w = readWriteLock.writeLock();

// 读操作上读锁
public Data get(String key) {
  r.lock();
  try { 
      // TODO 业务逻辑
  }finally { 
       r.unl
  • 8
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值