「java.util.concurrent并发包」之 ReentrantReadWriteLock
一 引言
在多线程的环境下,对同一份数据进行读写,会涉及到线程安全的问题。比如在一个线程读取数据的时候,另外一个线程在写数据,而导致前后数据的不一致性;一个线程在写数据的时候,另一个线程也在写,同样也会导致线程前后看到的数据的不一致性。这时候可以在读写方法中加入互斥锁,任何时候只能允许一个线程的一个读或写操作,而不允许其他线程的读或写操作,这样是可以解决这样以上的问题,但是效率却大打折扣了。因为在真实的业务场景中,一份数据,读取数据的操作次数通常高于写入数据的操作,而线程与线程间的读读操作是不涉及到线程安全的问题,没有必要加入互斥锁,只要在读-写,写-写期间上锁就行了
读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,这是由jvm自己控制的。
ReentrantReadWriteLock是可重入的读写锁,允许多个读线程获得ReadLock,但只允许一个写线程获得WriteLock
二 准备
读写锁的机制:
ReadWriteLock rtLock = new ReentrantReadWriteLock();
rtLock.readLock().lock();
System.out.println("get readLock.");
rtLock.writeLock().lock();
System.out.println("blocking");
锁升级
这个代码会死锁,没释放读锁就去申请写锁
ReadWriteLock rtLock = new ReentrantReadWriteLock();
rtLock.writeLock().lock();
System.out.println("writeLock"); rtLock.readLock().lock();
System.out.println("get read lock");
锁降级
以上这段代码虽然不会导致死锁,但没有正确的释放锁。从写锁降级成读锁,并不会自动释放当前线程获取的写锁,仍然需要显示的释放,否则别的线程永远也获取不到写锁。
三 javadoc的例子
class CachedData {
Object data;
volatile boolean cacheValid;
final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
public 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;
}
// 在释放写锁之前通过获取读锁降级写锁(注意此时还没有释放写锁)
rwl.readLock().lock();
} finally {
rwl.writeLock().unlock(); // 释放写锁而此时已经持有读锁
}
}
try {
use(data);
} finally {
rwl.readLock().unlock();
}
}
}
ReadWriteLock实例
注意最后的释放写锁「line21」,在之前是要加读锁「line19」的,因为在get过程中,可能有其他线程竞争到锁或是更新数据,会产生脏读。
private static Map<Integer, Integer> cache = Maps.newHashMap();
private ReadWriteLock readWriteLock = new ReentrantReadWriteLock(); public Integer get(Integer key) {
Integer value;
readWriteLock.readLock().lock();
try {
value = cache.get(key);
if (value == null) {
readWriteLock.readLock().unlock();
readWriteLock.writeLock().lock();
try {
if (value == null) {
value = 1; // 从数据库读取等
}
readWriteLock.readLock().lock();
} finally {
readWriteLock.writeLock().unlock();
}
}
} finally {
readWriteLock.readLock().unlock();
}
return value;
} public void put(Integer key, Integer value) {
readWriteLock.writeLock().lock();
cache.put(key, value);
readWriteLock.writeLock().unlock();
}
缓存
「java.util.concurrent并发包」之 ReentrantReadWriteLock的更多相关文章
- 「java.util.concurrent并发包」之 ThreadPoolExecutor
一 异步用new Thread? 大写的"low"!! new Thread(new Runnable() { @Override public void run() { // T ...
- 「java.util.concurrent并发包」之 CountDownLatch
一 CountDownLatch是什么 CountDownLatch是在java1.5被引入的,跟它一起被引入的并发工具类还有CyclicBarrier.Semaphore.ConcurrentHas ...
- 「java.util.concurrent并发包」之 CopyOnWrite
一 CopyOnWrite容器概述 Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容C ...
- 「java.util.concurrent并发包」之 CAS
一 引言 在JDK 5之前Java语言是靠synchronized关键字保证同步的,这会导致有锁 锁机制存在以下问题: (1)在多线程竞争下,加锁.释放锁会导致比较多的上下文切换和调度延时,引起性能 ...
- 「java.util.concurrent并发包」之 CyclicBarrier
一 描述 CyclicBarrier初始化时规定一个数目,然后计算调用了CyclicBarrier.await()进入等待的线程数.当线程数达到了这个数目时,所有进入等待状态的线程被唤醒并继续.Cyc ...
- Java并发:多线程和java.util.concurrent并发包总结
多线程和java.util.concurrent并发包 转载:
- Java并发—java.util.concurrent并发包概括(转载)
一.描述线程的类:Runable和Thread都属于java.lang包 二.内置锁synchronized属于jvm关键字,内置条件队列操作接口Object.wait()/notify()/noti ...
- java.util.concurrent并发包诸类概览
java.util.concurrent包的类都来自于JSR-166:Concurrent Utilities,官方的描述叫做“The JSR proposes a set of medium-lev ...
- java多线程---------java.util.concurrent并发包----------等待多线程完成
一.等待多线程完成的join的使用.CoundownLantch.CyclicBarrier .
随机推荐
- [Luogu] 无线网络发射器选址
https://www.luogu.org/problemnew/show/P2038 二维前缀和 #include <iostream> #include <cstdio> ...
- 我理解的windows中断管理
只谈外部中断的windows内核管理,异常和trap不在此文的讨论之列. 1. windows中断总貌 在windows中,物理上的中断源被抽象为KINTERRUPT结构.一个中断源在windows中 ...
- 用HQL自己写了个update!!!
原来代码: public void updateSj(String jsly, Integer zu,String sj) { if (!StringUtils.isBlank(jsly)&& ...
- Linux设备驱动程序 之 原子操作
原子整数操作 当共享资源是一个简单的整数值时,可以使用内核提供的一种原子的整数类型,称为atomic_t,定义在<linux/types.h>中,操作定义在<linux/atomic ...
- (转)ON DUPLICATE KEY UPDATE --mysql的一个有趣语法
转自:http://my.oschina.net/iceman/blog/53735?fromerr=3kAEPcQr 如果在INSERT语句末尾指定了ON DUPLICATE KEY UPDATE, ...
- jetbrains 2019 激活 error 1653219 解决办法
我以前用PyCharm按照http://idea.lanyus.com/上的激活码直接可激活. 后来用到IDEA(最新版)了之后激活报错.错误代码为1653219. 后参考博客 解决办法: 把host ...
- 关于go module
从Go 1.11开始引入module,用于版本管理. 通过使用module,工程目录的位置不用必须放在GOPATH下. 当前版本是1.13,下文中将以Go1.13为例介绍module. 在Go 1.1 ...
- IDEA快捷键(修改成eclipse版)+Templates
快捷键:使用快捷键需要下载改建的配置文件,默认eclipse版的按键还是不全的. 链接:https://pan.baidu.com/s/17H4tFh__k6rExGpAf8NRJg 密码:rnl3 ...
- linux文件结构---转发
linux各文件夹的作用---转载 linux下的文件结构,看看每个文件夹都是干吗用的/bin 二进制可执行命令 /dev 设备特殊文件 /etc 系统管理和配置文件 /etc/rc.d 启动的配 ...
- charles重发网络请求&模拟慢速网络&过滤网络请求
重发网络请求&模拟慢速网络&过滤网络请求 重发网络请求:后端调试的过程中,一直在客户端进行点点点比较麻烦,此时直接发送请求比较方便查看调试后的结果 模拟慢速网络:用户的网络不能一直是快 ...