简单地缓存系统:当有线程来取数据时,如果该数据存在我的内存中,我就返回数据;如果不存在我的缓存系统中,那么就去查数据库,返回数据的同时保存在我的缓存中。

其中涉及到读写问题:当多个线程执行读操作时(都加读锁),如果有数据返回;如果没有数据时,则让第一个读的线程,进行获取数据,然后进行写操作,这时需要第一个线程先释放掉读锁然后加写锁。第一个写完后,在家读锁,其他线程使用时判断,如果存在该数据,在直接过去读取不用加写锁。

API上缓存例子如下:

 class CachedData {Object data;volatile boolean cacheValid;ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();void processCachedData() {rwl.readLock().lock();if (!cacheValid) {// Must release read lock before acquiring write lockrwl.readLock().unlock();rwl.writeLock().lock();// Recheck state because another thread might have acquired//   write lock and changed state before we did.if (!cacheValid) {data = ...cacheValid = true;}// Downgrade by acquiring read lock before releasing write lockrwl.readLock().lock();rwl.writeLock().unlock(); // Unlock write, still hold read}use(data);rwl.readLock().unlock();}}
ReentrantReadWriteLock

此类具有以下属性:

  • 获取顺序

    此类不会将读取者优先或写入者优先强加给锁访问的排序。但是,它确实支持可选的公平 策略。

    非公平模式(默认)
    当非公平地(默认)构造时,未指定进入读写锁的顺序,受到 reentrancy 约束的限制。连续竞争的非公平锁可能无限期地推迟一个或多个 reader 或 writer 线程,但吞吐量通常要高于公平锁。
    公平模式
    当公平地构造线程时,线程利用一个近似到达顺序的策略来争夺进入。当释放当前保持的锁时,可以为等待时间最长的单个 writer 线程分配写入锁,如果有一组等待时间大于所有正在等待的 writer 线程 的 reader 线程,将为该组分配写入锁。

    如果保持写入锁,或者有一个等待的 writer 线程,则试图获得公平读取锁(非重入地)的线程将会阻塞。直到当前最旧的等待 writer 线程已获得并释放了写入锁之后,该线程才会获得读取锁。当然,如果等待 writer 放弃其等待,而保留一个或更多 reader 线程为队列中带有写入锁自由的时间最长的 waiter,则将为那些 reader 分配读取锁。

    试图获得公平写入锁的(非重入地)的线程将会阻塞,除非读取锁和写入锁都自由(这意味着没有等待线程)。(注意,非阻塞 ReentrantReadWriteLock.ReadLock.tryLock()ReentrantReadWriteLock.WriteLock.tryLock() 方法不会遵守此公平设置,并将获得锁(如果可能),不考虑等待线程)。

  • 重入

    此锁允许 reader 和 writer 按照 ReentrantLock 的样式重新获取读取锁或写入锁。在写入线程保持的所有写入锁都已经释放后,才允许重入 reader 使用它们。

    此外,writer 可以获取读取锁,但反过来则不成立。在其他应用程序中,当在调用或回调那些在读取锁状态下执行读取操作的方法期间保持写入锁时,重入很有用。如果 reader 试图获取写入锁,那么将永远不会获得成功。

  • 锁降级

    重入还允许从写入锁降级为读取锁,其实现方式是:先获取写入锁,然后获取读取锁,最后释放写入锁。但是,从读取锁升级到写入锁是不可能的

  • 锁获取的中断

    读取锁和写入锁都支持锁获取期间的中断。

  • Condition 支持

    写入锁提供了一个 Condition 实现,对于写入锁来说,该实现的行为与 ReentrantLock.newCondition() 提供的 Condition 实现对 ReentrantLock 所做的行为相同。当然,此 Condition 只能用于写入锁。

    读取锁不支持 ConditionreadLock().newCondition() 会抛出 UnsupportedOperationException

  • 监测

    此类支持一些确定是保持锁还是争用锁的方法。这些方法设计用于监视系统状态,而不是同步控制。

java实现如下:

package andy.thread.test;import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;/*** @author Zhang,Tianyou* @version 2014年11月9日 上午9:29:42*/public class ThreadCaChe {private static Map<String, Object> cacheMap = new HashMap<String, Object>();public static void main(String[] args) {for (int i = 0; i < 10; i++) {new Thread(new Runnable() {@Overridepublic void run() {String obj = (String) getData("andy");System.out.println(obj);}}).start();}}public static Object getData(String key) {ReadWriteLock rwlLock = new ReentrantReadWriteLock();// 先加读锁rwlLock.readLock().lock();Object value = null;try {value = cacheMap.get(key);// 若不存在cache中if (value == null) {// 若果value为空 则释放掉读锁,让该线程获取写锁,而其他线程只能等待该写锁释放,才能在进读锁rwlLock.readLock().unlock();// 加写锁rwlLock.writeLock().lock();try {if (value == null) {// 从数据中获取数据value = "andy is shuai ge";// 查询数据库// 存入缓存中cacheMap.put(key, value);}} finally {rwlLock.writeLock().unlock();}rwlLock.readLock().lock();}} finally {// 释放第一次获取的读锁rwlLock.readLock().unlock();}return value;}
}

执行效果如下:

andy is shuai ge
andy is shuai ge
andy is shuai ge
andy is shuai ge
andy is shuai ge
andy is shuai ge
andy is shuai ge
andy is shuai ge
andy is shuai ge
andy is shuai ge

多线程之使用读写锁ReentrantReadWriteLock实现缓存系统相关推荐

  1. android读写锁,ReentrantReadWriteLock读写锁及其在 RxCache 中的使用

    一. ReentrantReadWriteLock读写锁 Lock 是相当于 synchronized 更面向对象的同步方式,ReentrantLock 是 Lock 的实现. 本文要介绍的 Reen ...

  2. 并发编程-19AQS同步组件之重入锁ReentrantLock、 读写锁ReentrantReadWriteLock、Condition

    文章目录 J.U.C脑图 ReentrantLock概述 ReentrantLock 常用方法 synchronized 和 ReentrantLock的比较 ReentrantLock示例 读写锁R ...

  3. java 可重入读写锁 ReentrantReadWriteLock 详解

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt206 读写锁 ReadWriteLock读写锁维护了一对相关的锁,一个用于只 ...

  4. 深入分析实战可重入读写锁ReentrantReadWriteLock

    文章目录 前言 加锁规则 同步原理 源码解析 实战演示 前言 前面我们学习了可重入锁ReentrantLock,可重入锁是一个排他锁,只要不是当前线程访问加锁资源都不能够进入,只能等待锁的释放.当然, ...

  5. Oracle java官网关于可重入读写锁ReentrantReadWriteLock的解析

    Oracle java官网关于可重入读写锁ReentrantReadWriteLock的解析 1.[原文链接](https://docs.oracle.com/javase/8/docs/api/ja ...

  6. Java Review - 并发编程_读写锁ReentrantReadWriteLock的原理源码剖析

    文章目录 ReentrantLock VS ReentrantReadWriteLock 类图结构 非公平的读写锁实现 写锁的获取与释放 void lock() void lockInterrupti ...

  7. 深入理解读写锁ReentrantReadWriteLock

    深入理解读写锁ReentrantReadWriteLock 前言 业务开发中我们可能涉及到读写操作. 面对写和读,对于数据同步,在使用Lock锁和 synchronized关键字同步数据时候,对于读读 ...

  8. 读写锁ReentrantReadWriteLock:读读共享,读写互斥,写写互斥

    JDK1.5之后,提供了读写锁ReentrantReadWriteLock,读写锁维护了一对锁,一个读锁,一个写锁,通过分离读锁和写锁,使得并发性相比一般的排他锁有了很大提升.在读多写少的情况下,读写 ...

  9. Java多线程编程之读写锁【ReentrantReadWriteLock】

    有时候我们需要有这样的需求:         对于同一个文件进行读和写操作,普通的锁是互斥的,这样读的时候会加锁,只能单线程的读,我们希望多线程的进行读操作,并且读的时候不能进行写操作,写的时候不能进 ...

  10. Java多线程读写锁ReentrantReadWriteLock原理详解

    ReentrantLock属于排他锁,这些锁在同一时刻只允许一个线程进行访问,而读写锁在同一时刻可以允许多个线程访问,但是在写线程访问时,所有的读和其他写线程都被阻塞.读写锁维护了一对锁,一个读锁和一 ...

最新文章

  1. Linux下stat + 文件名后, Access,Modify,Change的含义
  2. jsp打印日志完整配置
  3. 获取自定义组件的宽度和高度
  4. Java 进阶 ——2019 计划要读的书
  5. 努力,做个淡定的女子
  6. Hadoop精华问答 | NameNode的工作特点
  7. 使用openswan构建lan-to-lan ×××(KLIPS)
  8. 【安卓笔记】—— 感知生命周期 Lifecycles
  9. 如何在JUnit4中按特定顺序运行测试方法?
  10. 清除tomcat缓存
  11. 简单介绍几种Java后台开发常用框架组合
  12. 软考网络工程师考试大纲
  13. 微信下载app需要点击右上角在浏览器中打开下载的解决办法
  14. win10卸载db2_怎么在windows下正确卸载DB2
  15. 基于java+mysql的Swing+MySQL图书管理系统(java+swing+gui+mysql)
  16. 微信小程序emoji表情输入框制作
  17. div样式之margin
  18. 长沙理工大学计算机与通信工程学院院长,徐蔚鸿教授
  19. SwiftUI Core Haptics 基础教程
  20. linux创建用户,并确定该用户所在组

热门文章

  1. 中山大学计算机学院官网万海,中山大学
  2. 首届电子商务AI算法大赛 Organized by automlai
  3. python实现mapreduce求平均值
  4. 从马克思看计算机科学,从马克思主义的角度,用科学精神来看生死观,应该说已经解决,或...
  5. html5绘制警告牌,2.10 创建自定义图形:绘制扑克牌花色 - HTML5 Canvas 实战
  6. spring 注解_Spring 注解编程之 AnnotationMetadata
  7. python编程*三角形图形创意图片_Python图形编程探索系列-04-网上图片与标签组件的结合...
  8. html显示实时时间_珠海体育场LED显示屏实时播放比赛时间
  9. Gibbs 采样完整解析与理解
  10. 计算机网络超详细笔记(三):数据链路层