🌈hello,你好鸭,我是Ethan,西安电子科技大学大三在读,很高兴你能来阅读。
✔️目前博客主要更新Java系列、项目案例、计算机必学四件套等。
🏃人生之义,在于追求,不在成败,勤通大道。加油呀!
🔥个人主页:Ethan Yankang
🔥推荐:史上最强八股文||一分钟看完我的几百篇博客
🔥温馨提示:划到文末发现专栏彩蛋 点击这里直接传送
🔥本篇概览:详细讲解了Java并发编程——互斥3——读写锁,基于ReadWriteLock开发高性能缓存🌈⭕🔥
【计算机领域一切迷惑的源头都是基本概念的模糊,算法除外】
🌈序言:
JAVA并发编程一直是难点,痛点,但又是进阶之重点,此关必过。今日得《冰河技术》之良品辅助,应按本系列学之习之,时时复习,长此以往必能穿魂入脉,习得大功。
记住——别违背科学发展的客观规律。别一味地赶进度以满足自己学的都么快的虚荣心,自欺欺人,要老老实实的走好每一步。
【并发编程全貌】
🔥Java并发编程全集
🌈引出:
读写锁
- 一个共享变量允许同时被多个读线程读取到。
- 一个共享变量在同一时刻只能被一个写线程进行写操作。
- 一个共享变量在被写线程执行写操作时,此时这个共享变量不能被读线程执行读操作。[反之亦然]
[但是如果是自身可以在持有写锁的情况下,自身可以获取读锁,因为这叫锁重入与降级,保证一致性]
这里,需要小伙伴们注意的是:读写锁和互斥锁的一个重要的区别就是:读写锁允许多个线程同时读共享变量,而互斥锁不允 许。所以,在高并发场景下,读写锁的性能要高于互斥锁。但是,读写锁的写操作是互斥的,也就是说,使用读写锁时,一个共 享变量在被写线程执行写操作时,此时这个共享变量不能被读线程执行读操作。[也就是对写锁互斥嘛,针对同一变量只能存在一个]
public ReentrantReadWriteLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
readerLock = new ReadLock(this);
writerLock = new WriteLock(this);
}
缓存实现
public class ReadWriteLockCache<K, V> {
private final Map<K, V> m = new HashMap<>();
private final ReadWriteLock rwl = new ReentrantReadWriteLock();
// 读锁
private final Lock r = rwl.readLock();
// 写锁
private final Lock w = rwl.writeLock();
// 读缓存
public V get(K key) {
r.lock();
try {
return m.get(key);
} finally {
r.unlock();
}
}
// 写缓存
public V put(K key, V value) {
w.lock();
try {
return m.put(key, value);
} finally {
w.unlock();
}
}
}
全量加载缓存
public class ReadWriteLockCache<K, V> {
private final Map<K, V> m = new HashMap<>();
private final ReadWriteLock rwl = new ReentrantReadWriteLock();
// 读锁
private final Lock r = rwl.readLock();
// 写锁
private final Lock w = rwl.writeLock();
public ReadWriteLockCache(){
//查询数据库
List<Field<K, V>> list = .....;
if(!CollectionUtils.isEmpty(list)){
list.parallelStream().forEach((f) ->{
m.put(f.getK(), f.getV);});
}
}
// 读缓存
public V get(K key) {
r.lock();
try {
return m.get(key);
} finally {
r.unlock();
}
}
// 写缓存
public V put(K key, V value) {
w.lock();
try {
return m.put(key, value);
} finally {
w.unlock();
}
}
}
按需加载缓存
class ReadWriteLockCache<K, V> {
private final Map<K, V> m = new HashMap<>();
private final ReadWriteLock rwl = new ReentrantReadWriteLock();
private final Lock r = rwl.readLock();
private final Lock w = rwl.writeLock();
V get(K key) {
V v = null;
//读缓存
r.lock();
try {
v = m.get(key);
} finally{
r.unlock();
}
//缓存中存在,返回
if(v != null) {
return v;
}
//缓存中不存在,查询数据库
w.lock();
try {
//再次验证缓存中是否存在数据,可能有线程已经写入
v = m.get(key);
if(v == null){
//查询数据库
v=从数据库中查询出来的数据
m.put(key, v);
}
} finally{
w.unlock();
}
return v;
}
}
读写锁的升降级
升级是指:读锁升级为写锁。降级是指写锁降级为读锁。
[可不,写互斥,读共享,当然互斥的级别高]
读写锁的策略是——不支持升级,但支持降级
实际上这里有专业说法——“写锁饥饿”写锁饥饿指的是真正需要写锁的线程因为其他线程升级锁的操作,而一直无法获得写锁,导致可能永久等待,甚至发生死锁的风险
class CachedData {
Object data;
volatile boolean cacheValid;
final 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();
try {
// 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();
} finally {
rwl.writeLock().unlock(); // Unlock write, still hold read
}
}
try {
use(data);
} finally {
rwl.readLock().unlock();
}
}
}
}
这里的代码块中,这个片段很有讲究:
rwl.readLock().lock(); // 1. 获取读锁
} finally {
rwl.writeLock().unlock(); // 2. 释放写锁,但仍持有读锁
}
这是在本线程还未释放写锁的情况下,获取了自身的读锁,这成为锁重入。之后在通过释放了写锁完成了锁降级——从写—>读。
锁降级的用途
一般这种用法在于线程想要修改共享资源,修改了后可以确保立即对其他线程可见,但是希望该共享资源依然受锁保护,而且本线程仍然可以实现对共享资源的监督与保护的情景。
锁降级的步骤
结合上面的情景,共有四大步:
获取写锁——>[重入]获取读锁——>释放写锁——>释放写锁
[读写读写!]
锁降级的目的
这是为了保证在自身修改完数据后,防止其他线程来修改数据,所以在这期间一直未有释放写锁,直至获取了读锁之后,确保自身就算释放了锁,也不会被其他线程修改数据,确保了数据的一致性。同时,降级后本线程依然有锁,这样实现了释放读锁后的共享资源监控与保护,本线程仍然可以感知共享资源的并保证其一致性
数据同步问题【双写一致问题】
💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖
热门专栏推荐
🌈🌈计算机科学入门系列 关注走一波💕💕
🌈🌈CSAPP深入理解计算机原理 关注走一波💕💕
🌈🌈微服务项目之黑马头条 关注走一波💕💕
🌈🌈redis深度项目之黑马点评 关注走一波💕💕
🌈🌈JAVA面试八股文系列专栏 关注走一波💕💕
🌈🌈JAVA基础试题集精讲 关注走一波💕💕
🌈🌈代码随想录精讲200题 关注走一波💕💕
总栏
🌈🌈JAVA基础要夯牢 关注走一波💕💕
🌈🌈JAVA后端技术栈 关注走一波💕💕
🌈🌈JAVA面试八股文 关注走一波💕💕
🌈🌈JAVA项目(含源码深度剖析) 关注走一波💕💕
🌈🌈计算机四件套 关注走一波💕💕
🌈🌈数据结构与算法 关注走一波💕💕
🌈🌈必知必会工具集 关注走一波💕💕
🌈🌈书籍网课笔记汇总 关注走一波💕💕
📣非常感谢你阅读到这里,如果这篇文章对你有帮助,希望能留下你的点赞👍 关注❤收藏✅ 评论💬,大佬三连必回哦!thanks!!!
📚愿大家都能学有所得,功不唐捐!