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 如何使用?的更多相关文章

  1. 基于synchronized 或 ReadWriteLock实现 简单缓存机制

    package cn.xxx.xxx; import java.util.HashMap; import java.util.Map; import java.util.concurrent.lock ...

  2. java 多线程(ReadWriteLock)

    package com.example; public class App { public static void main(String[] args) { Info info = new Inf ...

  3. java5 ReadWriteLock用法--读写锁实现

    读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,这是由jvm自己控制的,你只要上好相应的锁即可.如果你的代码只读数据,可以很多人同时读,但不能同时写,那就上读锁:如果你的代码修改数据,只能有一 ...

  4. 读写锁:ReadWriteLock

    http://my.oschina.net/20076678/blog/173165   一.在JDK文档中关于读写锁的相关说明 ReadWriteLock 维护了一对相关的 锁 ,一个用于只读操作, ...

  5. Java Concurrency - ReadWriteLock & ReentrantReadWriteLock

    锁所提供的最重要的改进之一就是 ReadWriteLock 接口和它的实现类 ReentrantReadWriteLock.这个类提供两把锁,一把用于读操作和一把用于写操作.同一时间可以有多个线程执行 ...

  6. 读写锁ReadWriteLock和缓存实例

    读写锁:多个读锁不互斥,读锁与写锁互斥,写锁与写锁互斥.即:读的时候不允许写,写的时候不允许读,可以同时读.      synchronized关键字和普通的Lock构造的锁,会造成读与读之间的互斥, ...

  7. java 5 ReadWriteLock

    import java.util.ArrayList; import java.util.List; import java.util.concurrent.locks.ReadWriteLock; ...

  8. ReadWriteLock与ReentrantReadWriteLock

    JAVA的JUC包中的锁包括"独占锁"和"共享锁".JUC中的共享锁有:CountDownLatch.CyclicBarrier.Semaphore.Reent ...

  9. 利用readwritelock简单模拟实现多线程下cache的系统

    package cn.lyy.hibernate.many2one; import java.util.HashMap; import java.util.Map; import java.util. ...

  10. 同步中的四种锁synchronized、ReentrantLock、ReadWriteLock、StampedLock

    目录 1.synchronized同步锁 2.ReentrantLock重入锁 3.ReadWriteLock读写锁 4.StampedLock戳锁(目前没找到合适的名字,先这么叫吧...) 5.总结 ...

随机推荐

  1. slim.arg_scope()的使用

    [https://blog.csdn.net/u013921430 转载] slim是一种轻量级的tensorflow库,可以使模型的构建,训练,测试都变得更加简单.在slim库中对很多常用的函数进行 ...

  2. Codeforces 19E&BZOJ 4424 Fairy(好题)

    日常自闭(菜鸡qaq).不过开心的是看了题解之后1A了.感觉这道题非常好,必须记录一下,一方面理清下思路,一方面感觉自己还没有完全领会到这道题的精髓先记下来以后回想. 题意:给定 n 个点,m 条边的 ...

  3. 【转载】网易极客战记官方攻略-地牢-严酷考验 B

    关卡连接:https://codecombat.163.com/play/level/the-gauntlet-b 免费试玩:https://codecombat.163.com/play 使用你的所 ...

  4. 2018CSS特效集锦牛逼

    https://tympanus.net/codrops/2018/12/27/awesome-demos-from-2018/

  5. js中数据操作的某些思想

    1,默认数据的复用 写成function的return形式缓存在变量中,用的时候直接执行fun就行了 例如 有文件text.js里面的对象是export default ()=>({aa:55, ...

  6. 代理端口转发工具rinetd

    转载: https://my.oschina.net/wuweixiang/blog/2983280 rinetd 前言 iptables 的功能当然强大,但理解与设置却有点抽象,便通过google认 ...

  7. Sql 语法整理

    Query 1 SELECT 和 SELECT * 语句 SELECT LastName,FirstName FROM Persons 2 SELECT DISTINCT 语句 SELECT DIST ...

  8. How To Use PostgreSQL with Your Ruby on Rails Application on Ubuntu 14.04

    How To Use PostgreSQL with Your Ruby on Rails Application on Ubuntu 14.04 链接来自于:https://www.digitalo ...

  9. 屏幕尺寸,分辨率,PPI,像素之间的关系

    什么是屏幕尺寸? 华为荣耀7的尺寸是5.2英寸.这个5.2英寸是手机屏幕对角线的长度. 1英寸(inch)=2.54厘米(cm) 什么是分辨率? 华为荣耀7的分辨率是1920PX*1080PX.像素是 ...

  10. 状态压缩dp增量统计贡献——cf1238E(好题)

    这题的状态设计非常巧妙,因为dp[S]表示的并非当前正确的值,而是维护一个中间量,这个中间量在到达末状态时才正确 当然官方的题解其实更加直观,只不过理解起来其实有点困难 /* 给定一个串s,字符集为2 ...