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.总结 ...
随机推荐
- MATLAB中图像处理的函数
表1 图像显示 函数名 功能说明 函数名 功能说明 colorbar 颜色条显示 montage 按矩形剪辑方式显示多帧图像 getimage 从坐标系中获取图像数据 immovie 从多帧索引图像中 ...
- PHP-缺失的第一个正数
给定一个未排序的整数数组,找出其中没有出现的最小的正整数. 示例 1: 输入: [1,2,0]输出: 3示例 2: 输入: [3,4,-1,1]输出: 2示例 3: 输入: [7,8,9,11,12] ...
- gif,jpg(jpeg),png,webp,base64图片格式比较
对于web前端开发的同学来说,图片保存格式非常的重要.那么该如何选择图片保存的格式呢?下面我总结一下gif,jpg,png等图片格式的区别. gif是很早应用的一种图片格式.它采用的是lzw的压缩算法 ...
- leetcode-160周赛-5239-循环码排列
题目描述: 参考格雷编码: class Solution: def circularPermutation(self, n: int, start: int) -> List[int]: res ...
- Windows cmd 打开面板
{ 打开控制面板的命令是:“control” 打开控制面板 命令: rundll32.exe shell32.dll,Control_RunDLL 结果: 显示控制面板窗口. 例子: Cal ...
- sql delete语句
如果要删除数据库表中的记录,我们可以使用DELETE语句. DELETE语句的基本语法是: DELETE FROM <表名> WHERE ...; 例如,我们想删除students表中id ...
- [Go语言]cgo用法演示
经历了数十年发展的C语言,各种各样的现成的库已经非常丰富.通过cgo,可以在Go语言中使用C语言代码,充分利用好现有的“轮子”. 本文所有代码,在下述环境中调试通过: Windows 8.1 ...
- 选择排序-Python & Java
选择排序:1.找出最小的数值放在第一位2.找出剩余数据中最小的数值放在第二位,以此类推,直到最后一个数值 算法的时间复杂度为:O(n) ''' 选择排序: 1.找出最小的数值放在第一位 2.找出剩余数 ...
- Idea 导入项目不能运行
1.项目结构里面配置sdk,配置output输出目录 2.配置语言等级 配置src源文件目录 配置目录里面添加application,添加main class
- PHP面试 PHP基础知识 八(会话控制)
---恢复内容开始--- PHP会话控制技术 首先了解一下为什么要使用会话控制技术? 本身web 与服务器的交互是通过HTTP协议来实现的,而HTTP协议又是无状态协议.就是说明HTTP协议没有一个內 ...