搞定ReentrantReadWriteLock 几道小小数学题就够了

| 好看请赞,养成习惯

你有一个思想,我有一个思想,我们交换后,一个人就有两个思想

If you can NOT explain it simply, you do NOT understand it well enough

现陆续将Demo代码和技术文章整理在一起 Github实践精选 ,方便大家阅读查看,本文同样收录在此,觉得不错,还请Star

搞定ReentrantReadWriteLock 几道小小数学题就够了

前言

文章 Java AQS队列同步器以及ReentrantLock的应用 介绍了AQS独占式获取同步状态的实现,并以 ReentrantLock 为例说明其是如何自定义同步器实现互斥锁的

文章 Java AQS共享式获取同步状态及Semaphore的应用分析 介绍 AQS 共享式获取同步状态的实现,并说明了 Semaphore 是如何自定义同步器实现简单限流作用的

有了以上两篇文章的铺垫,来理解本文要介绍的既有独占式,又有共享式获取同步状态的 ReadWriteLock,就非常轻松了

搞定ReentrantReadWriteLock 几道小小数学题就够了

ReadWriteLock

ReadWriteLock 直译过来为【读写锁】。现实中,读多写少的业务场景是非常普遍的,比如应用缓存

一个线程将数据写入缓存,其他线程可以直接读取缓存中的数据,提高数据查询效率

之前提到的互斥锁都是排他锁,也就是说同一时刻只允许一个线程进行访问,当面对可共享读的业务场景,互斥锁显然是比较低效的一种处理方式。为了提高效率,读写锁模型就诞生了

效率提升是一方面,但并发编程更重要的是在保证准确性的前提下提高效率

一个写线程改变了缓存中的值,其他读线程一定是可以 “感知” 到的,否则可能导致查询到的值不准确

所以关于读写锁模型就了下面这 3 条规定:

允许多个线程同时读共享变量

只允许一个线程写共享变量

如果写线程正在执行写操作,此时则禁止其他读线程读共享变量

ReadWriteLock 是一个接口,其内部只有两个方法:

public interface ReadWriteLock { // 返回用于读的锁 Lock readLock(); // 返回用于写的锁 Lock writeLock(); }

所以要了解整个读/写锁的整个应用过程,需要从它的实现类 ReentrantReadWriteLock 说起

ReentrantReadWriteLock 类结构

直接对比ReentrantReadWriteLock 与 ReentrantLock的类结构

搞定ReentrantReadWriteLock 几道小小数学题就够了

他们又很相似吧,根据类名称以及类结构,按照咱们前序文章的分析,你也就能看出 ReentrantReadWriteLock 的基本特性:

搞定ReentrantReadWriteLock 几道小小数学题就够了

其中黄颜色标记的的 锁降级 是看不出来的, 这里先有个印象,下面会单独说明

另外,不知道你是否还记得,Java AQS队列同步器以及ReentrantLock的应用 说过,Lock 和 AQS 同步器是一种组合形式的存在,既然这里是读/写两种锁,他们的组合模式也就分成了两种:

读锁与自定义同步器的聚合

写锁与自定义同步器的聚合

public ReentrantReadWriteLock(boolean fair) { sync = fair ? new FairSync() : new NonfairSync(); readerLock = new ReadLock(this); writerLock = new WriteLock(this); }

搞定ReentrantReadWriteLock 几道小小数学题就够了

这里只是提醒大家,模式没有变,不要被读/写两种锁迷惑

基本示例

说了这么多,如果你忘了前序知识,整体理解感觉应该是有断档的,所以先来看个示例(模拟使用缓存)让大家对 ReentrantReadWriteLock 有个直观的使用印象

public class ReentrantReadWriteLockCache { // 定义一个非线程安全的 HashMap 用于缓存对象 static Map<String, Object> map = new HashMap<String, Object>(); // 创建读写锁对象 static ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); // 构建读锁 static Lock rl = readWriteLock.readLock(); // 构建写锁 static Lock wl = readWriteLock.writeLock(); public static final Object get(String key) { rl.lock(); try{ return map.get(key); }finally { rl.unlock(); } } public static final Object put(String key, Object value){ wl.lock(); try{ return map.put(key, value); }finally { wl.unlock(); } } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wppfdf.html