并发编程(十二):ReadWriteLock

【关于作者】

关于作者,目前在蚂蚁金服搬砖任职,在支付宝营销投放领域工作了多年,目前在专注于内存数据库相关的应用学习,如果你有任何技术交流或大厂内推及面试咨询,都可以从我的个人博客(https://0522-isniceday.top/)联系我

前面我们介绍了管程和信号量这两个同步原语在 Java 语言中的实现,理论上用这两个同步原语中任何一个都可以解决所有的并发问题。那 Java SDK 并发包里为什么还有很多其他的工具类呢?原因很简单:分场景优化性能,提升易用性

1.读写锁:ReadWriteLock

读写锁:

  1. 允许多个线程同时读共享变量
  2. 只允许一个线程写共享变量
  3. 如果一个线程正在执行写操作,此时限制读线程读共享变量

1.1.互斥锁与读写锁的重要区别以及适用场景

  1. 读写锁允许多个线程同时读共享变量,而互斥锁不允许
  2. 在读多写少的场景,读写锁的性能明显优于互斥锁

2.读写锁的注意点

2.1.关于锁升级和锁降级

锁升级:如果当前线程已经拿到了读锁,此时如果再去拿写锁(升级为写锁),这个过程称为锁升级,但是ReadWriteLock 不支持锁升级,此时会发生死锁,示例如下:

final ReadWriteLock rwl = new ReentrantReadWriteLock();
// 读锁  
final Lock readLock = rwl.readLock();
// 写锁
final Lock writeLock = rwl.writeLock();    

try {
      //先拿到读锁
      readLock.lock();
      //再拿到写锁,此时会发生锁升级以及死锁问题,类似mysql的读锁
      writeLock.lock();
      System.out.println("拿到写锁拉");
      System.out.println("锁降级拉");
      for (int i = 0; i < time; i++) {
        System.out.println("请求写锁:"+i+"秒");
        Thread.sleep(1000 * 1);
      }
    }finally {
      writeLock.unlock();
      readLock.unlock();
    }
  }

锁降级:如果当前线程拿到了写锁,此时如果再去上读锁(降级为读锁),这个过程称为锁降级,ReadWriteLock是支持的

其实读写锁的升级和降级或者说读写锁的上锁操作,其实也对应于MySQL的读锁和写锁:

xx.readLock()操作,其实就是相当于MySQL的读锁,只允许当前线程和其他线程上读锁,但是不允许上写锁,此时如果当前线程上了读锁又去上写锁(锁升级),就会出现死锁的场景

xx.writeLock操作,其实就是相当于MySQL的写锁,只允许当前线程(事务)上进行读写操作(上读锁和写锁),其余线程如果请求上写锁或读锁时,就会发送阻塞操作直至取得写锁的线程释放写锁。

总结一下:

  1. MySQL的读锁又上写锁,就是ReadWriteLock的锁升级的场景,但是ReadWriteLock不支持这个场景,并且会导致死锁

  2. MySQL的写锁的功能,就是ReadWriteLock的锁降级的过程

  3. ReadWriteLock的写锁已被申请之后,读锁只能等待写锁都被释放才能去上写锁,而读锁被申请后,其余线程还可以再次上读锁

  4. 读写锁中的每个线程只能释放自己线程申请的锁,否则释放锁的线程会抛出异常:

    image-20210816092050210

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哈哈哈张大侠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值