多线程之使用读写锁ReentrantReadWriteLock实现缓存系统
简单地缓存系统:当有线程来取数据时。假设该数据存在我的内存中。我就返回数据。假设不存在我的缓存系统中,那么就去查数据库。返回数据的同一时候保存在我的缓存中。
当中涉及到读写问题:当多个线程运行读操作时(都加读锁)。假设有数据返回;假设没有数据时。则让第一个读的线程。进行获取数据,然后进行写操作。这时须要第一个线程先释放掉读锁然后加写锁。第一个写完后,在家读锁。其它线程使用时推断,假设存在该数据,在直接过去读取不用加写锁。
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 lock
rwl.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 lock
rwl.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仅仅能用于写入锁。读取锁不支持
Condition,readLock().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() { @Override
public 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实现缓存系统的更多相关文章
- JAVA 并发编程-读写锁之模拟缓存系统(十一)
在多线程中,为了提高效率有些共享资源同意同一时候进行多个读的操作,但仅仅同意一个写的操作,比方一个文件,仅仅要其内容不变能够让多个线程同一时候读,不必做排他的锁定,排他的锁定仅仅有在写的时候须要,以保 ...
- Java并发指南10:Java 读写锁 ReentrantReadWriteLock 源码分析
Java 读写锁 ReentrantReadWriteLock 源码分析 转自:https://www.javadoop.com/post/reentrant-read-write-lock#toc5 ...
- Java多线程13:读写锁和两种同步方式的对比
读写锁ReentrantReadWriteLock概述 大型网站中很重要的一块内容就是数据的读写,ReentrantLock虽然具有完全互斥排他的效果(即同一时间只有一个线程正在执行lock后面的任务 ...
- java 可重入读写锁 ReentrantReadWriteLock 详解
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt206 读写锁 ReadWriteLock读写锁维护了一对相关的锁,一个用于只 ...
- Java并发(十):读写锁ReentrantReadWriteLock
先做总结: 1.为什么用读写锁 ReentrantReadWriteLock? 重入锁ReentrantLock是排他锁,在同一时刻仅有一个线程可以进行访问,但是在大多数场景下,大部分时间都是提供读服 ...
- 轻松掌握java读写锁(ReentrantReadWriteLock)的实现原理
转载:https://blog.csdn.net/yanyan19880509/article/details/52435135 前言 前面介绍了java中排它锁,共享锁的底层实现机制,本篇再进一步, ...
- 多线程编程_读写锁ReadWriteLock
Lock比传统线程模型中的synchronized方式更加面向对象,与生活中的锁类似,锁本身也应该是一个对象.两个线程执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象. 读写锁:分为读 ...
- [图解Java]读写锁ReentrantReadWriteLock
图解ReentrantReadWriteLock 如果之前使用过读写锁, 那么可以直接看本篇文章. 如果之前未使用过, 那么请配合我的另一篇文章一起看:[源码分析]读写锁ReentrantReadWr ...
- 读写锁ReentrantReadWriteLock:读读共享,读写互斥,写写互斥
介绍 DK1.5之后,提供了读写锁ReentrantReadWriteLock,读写锁维护了一对锁:一个读锁,一个写锁.通过分离读锁和写锁,使得并发性相比一般的排他锁有了很大提升.在读多写少的情况下, ...
随机推荐
- vue - dist
描述:打包后准备上线的文件(需要服务器环境才能运行!!!)
- Android获取前台进程的方法
概述 项目中很多场景交互非常依赖于客户端的前后景状态以及其他一些辅助信息上传,譬如当前新闻在前台(看到的是新闻界面)播放时,语音开启音乐应用,此时我们希望能看到音乐界面,并且音乐在播;而在导航应用在前 ...
- ionic中ionicView的生命周期
ionicView的生命周期的事件调用在每个ionicView的controller中使用$scope.$on('$ionicView.enter', function() {});调用. 1.$ i ...
- Jquery如何序列化form表单数据为JSON对象 C# ADO.NET中设置Like模糊查询的参数 从客户端出现小于等于公式符号引发检测到有潜在危险的Request.Form 值 jquery调用iframe里面的方法 Js根据Ip地址自动判断是哪个城市 【我们一起写框架】MVVM的WPF框架(三)—数据控件 设计模式之简单工厂模式(C#语言描述)
jquery提供的serialize方法能够实现. $("#searchForm").serialize();但是,观察输出的信息,发现serialize()方法做的是将表单中的数 ...
- 全面进攻python之前回顾下自己近三个月的自学之路
人生是在一直试错的过程中成长起来的.这句话貌似很有道理,但回顾了下自己近三个月python自学学习之路,又觉得自己对这句话又有了新的看法------行动之前必须要有正确的选择,这样做错了才能成长. 2 ...
- 怎样使用CSS3实现书页(书本)卷角效果
我们有时候想在页面显示一个公告或用户提示信息. 一个经常使用设计是使用书签形状. 我们能够给书签加入卷角效果.以使其更为逼真.所谓的"卷角"实际上能够用小角度倾斜的阴影效果来模拟. ...
- photoshop 动作 自己定义快捷键 播放选定的动作
今天在制作一组效果图.要用到动作.而且是同一个动作,便在网上寻找"播放选定的动作"就是那个三角形播放button的快捷键. 预期这样会大大加快制作过程. 首先制作好动作. 然后,在 ...
- 关于wxpy,使用Python玩转微信的问题
在github上下载了,安装了之后在idle上运行,好像是说Python不能上网.新手求助.现在问题已经解决,是ssl 证书的问题,不能用最新的 复制内容到剪贴板 代码: sudo pip unins ...
- springboot+springAOP实现数据库读写分离及数据库同步(MySQL)----最新可用2019-2-14
原文:https://blog.csdn.net/wsbgmofo/article/details/79260896 1,数据源配置文件,如下 datasource.readSize=1spring. ...
- 蓝牙(CoreBluetooth)-外部设备(服务端)
蓝牙(CoreBluetooth)-外部设备(服务端) 主要内容 1. 创建外部管理器对象 2. 设置本地外设的服务和特征 3. 添加服务和特征到到你的设置的数据库中 4. 向外公布你的的服务 5. ...