ReadWriteLock 如何使用?
QReadWriteLock从名字看就知道是读写锁的意思。和QMutex一样,QReadWriteLock也是线程同步的一种工具。那么它有什么用呢?和QMutex又有什么区别呢?写个例子瞧一瞧。
特点:
包含一个 ReadLock 和 一个 WriteLock 对象
读锁与读锁不互斥;读锁与写锁,写锁与写锁互斥
适合对共享资源有读和写操作,写操作很少,读操作频繁的场景
可以从写锁降级到读锁。获取写锁->获取读锁->释放写锁
无法从读锁升级到写锁
读写锁支持中断
写锁支持Condition;读锁不支持Condition
示例1--根据 key 获取 value 值
private ReadWriteLock lock = new ReentrantReadWriteLock();//定义读写锁
//根据 key 获取 value 值
public Object getValue(String key){
//使用读写锁的基本结构
lock.readLock().lock();//加读锁
Object value = null;
try{
value = cache.get(key);
if(value == null){
lock.readLock().unlock();//value值为空,释放读锁
lock.writeLock().lock();//加写锁,写入value值
try{
//重新检查 value值是否已经被其他线程写入
if(value == null){
value = "value";//写入数据
}
}finally{
lock.writeLock().unlock();
}
lock.readLock().lock();
}
}finally{
lock.readLock().unlock();
}
return value;
}
示例2--多线程环境下的读写锁使用
package constxiong.interview;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
* 测试可重入 读写锁
* @author ConstXiong
* @date 2019-06-10 11:19:42
*/
public class TestReentrantReadWriteLock {
private Map<String, Object> map = new HashMap<String, Object>();
private ReadWriteLock lock = new ReentrantReadWriteLock();
/**
* 根据 key 获取 value
* @param key
* @return
*/
public Object get(String key) {
Object value = null;
lock.readLock().lock();
try {
Thread.sleep(50L);
value = map.get(key);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.readLock().unlock();
}
return value;
}
/**
* 设置key-value
* @param key
* @return
*/
public void set(String key, Object value) {
lock.writeLock().lock();
try {
Thread.sleep(50L);
map.put(key, value);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.writeLock().unlock();
}
}
//测试5个线程读数据,5个线程写数据
public static void main(String[] args) {
final TestReentrantReadWriteLock test = new TestReentrantReadWriteLock();
final String key = "lock";
final Random r = new Random();
for (int i = 0; i < 5; i++) {
new Thread(){
@Override
public void run() {
for (int j = 0; j < 10; j++) {
System.out.println(Thread.currentThread().getName() + " read value=" + test.get(key));
}
}
}.start();
new Thread(){
@Override
public void run() {
for (int j = 0; j < 10; j++) {
int value = r.nextInt(1000);
test.set(key, value);
System.out.println(Thread.currentThread().getName() + " write value=" + value);
}
}
}.start();
}
}
}
公平性
非公平策略
当以非公平初始化时,读锁和写锁的获取的顺序是不确定的。非公平锁主张竞争获取,可能会延缓一个或多个读或写线程,但是会比公平锁有更高的吞吐量。
公平策略
当以公平模式初始化时,线程将会以队列的顺序获取锁。当当前线程释放锁后,等待时间最长的写锁线程就会被分配写锁;或者有一组读线程组等待时间比写线程长,那么这组读线程组将会被分配读锁。
可重入性
默认是可重入的但是要成对的获取锁和释放锁,如下的这段例子,主线程两次获取锁lock.writeLock().lock(),说明其实可重入的,但是输出结果是只有realse one once;因此thread1执行的时候尝试获取锁此时因为主线程未释放,也就导致了死锁。
public static void main(String[] args) throws InterruptedException {
final ReentrantReadWriteLock lock = new ReentrantReadWriteLock ();
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
lock.writeLock().lock();
System.out.println("Thread real execute");
lock.writeLock().unlock();
}
});
lock.writeLock().lock();
lock.writeLock().lock();
thread1.start();
Thread.sleep(200);
System.out.println("realse one once");
lock.writeLock().unlock();
}
在写例子前,先看看要用到的函数:lockForRead、lockForWrite和unlock。比QMutex的例子多一个,从名字上可以看得出来是把lock分为了readlock和writelock。unlock和QMutex里的是一样的,有lock就要unlock。
例子3:
1.从QThread派生一个类ReadThread,重写run函数。
其中gRwLock是一个QReadWriteLock类型的全局对象,run函数的作用就是简单的打印三句话。
2.创建两个ReadThread的对象并start。
看看运行结果:
两个线程还是交替运行的。这是什么情况?我的锁怎么没用呢?........没用就对了,QReadWriteLock是允许并行读的,当调用写锁时其他的lock就要等待。是时候让lockForWrite出场了。
3.再从QThread派生一个类WriteThread,外汇返佣http://www.fx61.com/重写run函数。
WriteThread的run函数里调用的是lockForWrite,锁住的也是三个qDebug。在刚才的基础上再创建一个WriteThread的对象看看运行效果。
运行结果可能会有差异,但是write的三句话始终会按顺序执行。这时候锁才发挥了它的作用。
总结:读写锁允许并行的读,如果遇到写锁时其它锁被锁住。写锁的优先级要高于读锁,如等待的锁中有读锁和写锁时,一旦上一个锁被解锁时会优先执行写锁。QReadWriteLock相对于QMutex的好处是当要保护的对象在大多数的情况是读操作偶尔写操作时,不会造成不必要的堵塞。
ReadWriteLock 如何使用?的更多相关文章
- 基于synchronized 或 ReadWriteLock实现 简单缓存机制
package cn.xxx.xxx; import java.util.HashMap; import java.util.Map; import java.util.concurrent.lock ...
- java 多线程(ReadWriteLock)
package com.example; public class App { public static void main(String[] args) { Info info = new Inf ...
- java5 ReadWriteLock用法--读写锁实现
读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,这是由jvm自己控制的,你只要上好相应的锁即可.如果你的代码只读数据,可以很多人同时读,但不能同时写,那就上读锁:如果你的代码修改数据,只能有一 ...
- 读写锁:ReadWriteLock
http://my.oschina.net/20076678/blog/173165 一.在JDK文档中关于读写锁的相关说明 ReadWriteLock 维护了一对相关的 锁 ,一个用于只读操作, ...
- Java Concurrency - ReadWriteLock & ReentrantReadWriteLock
锁所提供的最重要的改进之一就是 ReadWriteLock 接口和它的实现类 ReentrantReadWriteLock.这个类提供两把锁,一把用于读操作和一把用于写操作.同一时间可以有多个线程执行 ...
- 读写锁ReadWriteLock和缓存实例
读写锁:多个读锁不互斥,读锁与写锁互斥,写锁与写锁互斥.即:读的时候不允许写,写的时候不允许读,可以同时读. synchronized关键字和普通的Lock构造的锁,会造成读与读之间的互斥, ...
- java 5 ReadWriteLock
import java.util.ArrayList; import java.util.List; import java.util.concurrent.locks.ReadWriteLock; ...
- ReadWriteLock与ReentrantReadWriteLock
JAVA的JUC包中的锁包括"独占锁"和"共享锁".JUC中的共享锁有:CountDownLatch.CyclicBarrier.Semaphore.Reent ...
- 利用readwritelock简单模拟实现多线程下cache的系统
package cn.lyy.hibernate.many2one; import java.util.HashMap; import java.util.Map; import java.util. ...
- 同步中的四种锁synchronized、ReentrantLock、ReadWriteLock、StampedLock
目录 1.synchronized同步锁 2.ReentrantLock重入锁 3.ReadWriteLock读写锁 4.StampedLock戳锁(目前没找到合适的名字,先这么叫吧...) 5.总结 ...
随机推荐
- 解决vcenter 6.0 vcsa安装插件第二个的时候报错的问题
解决vcenter 6.0 vcsa安装插件第二个的时候报错的问题 需要打一下windows 的Microsoft v C++ 2013的2个补丁就可以正常运行了. 然后在后续安装过程中,到达最后一步 ...
- MySQL 复制参数详解
log-bin 二进制日志 server-id 早起版本必须添加 1-pow(2,32)-1 推荐使用 端口号+ip最后一位 5.6后可以动态修改 server-uuid (5.6以后) 默认存在 ...
- AE开发中实现Control中的各种图形工具的方法(转)
Controls中的工具基本可以分为两类: 第一类:点击工具图标或按钮后,当前axMapControl的工具即为所点击的工具命令. 前面有Controls 后面有tool的工具都可以用同一类的代码实现 ...
- leetcode-168周赛-1298-你能从盒子中获得的最大糖果数
题目描述: 方法一:bfs class Solution: def maxCandies(self, status: List[int], candies: List[int], keys: List ...
- 深入理解Magento – 第二章 – Magento请求分发与控制器
深入理解Magento 作者:Alan Storm 翻译:Hailong Zhang 第二章 – Magento请求分发与控制器 Model-View-Controller (MVC) ,模型-视图- ...
- Yii2 自定义组件
basic\components\HelloWidget namespace app\components; use yii\base\Widget; use yii\helpers\Html; cl ...
- Luogu P2042 [NOI2005]维护数列
题目描述 请写一个程序,要求维护一个数列,支持以下 6 种操作:(请注意,格式栏 中的下划线' _ '表示实际输入文件中的空格) 输入输出格式 输入格式: 输入文件的第 1 行包含两个数 N 和 M, ...
- SP7258 SUBLEX - Lexicographical Substring Search(后缀自动机)
传送门 解题思路 首先建\(sam\),然后在拓扑序上\(dp\)一下,把每个点的路径数算出来,然后统计答案时就在自动机上\(dfs\)一下,仿照平衡树那样找第\(k\)小. 代码 #include& ...
- I. Five Day Couple--“今日头条杯”首届湖北省大学程序设计竞赛(网络同步赛)
题目描述:链接点此 这套题的github地址(里面包含了数据,题解,现场排名):点此 链接:https://www.nowcoder.com/acm/contest/104/H来源:牛客网 题目描述 ...
- java 原生 HttpClient
package org.rx.socks.http; import com.google.common.base.Strings; import lombok.SneakyThrows; import ...