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. ORACLE PL、SQL编程

    PL(Procedural Language)过程化的编程语言,是在SQL的基础上增加的部分,如:变量的使用.流程控制等, 重点学习Oracle和MySQL创建存储过程及流程控制的异同. 一.存储过程 ...

  2. react 16.3+ 新生命周期 作业

    1.有哪些⽣命周期被舍弃(3个),哪些⽣命 周期是新增(2个)? componentWillMount().componentWillReceiveProps().componentWillUpdat ...

  3. ubuntu18.4 搭建lamp环境

    一.Apache2 web服务器的安装: 可以先更新一下服务器(可选) 1.sudo apt update             # 获取最新资源包 2.sudo apt upgrade       ...

  4. JS window对象 Navigator对象 Navigator 对象包含有关浏览器的信息,通常用于检测浏览器与操作系统的版本。

    Navigator对象 Navigator 对象包含有关浏览器的信息,通常用于检测浏览器与操作系统的版本. 对象属性: 查看浏览器的名称和版本,代码如下: <script type=" ...

  5. vCenter 6.0 vsca 安装遇到的一些小问题

    在安装vCenter 6.0 vsca的时候,安装插件到第二个的时候,会报出一个windows installer的错误.需要联系软件管理员或者技术支持的一个error. 经过多次的测试,我终于找到了 ...

  6. redis底层相关命令(一)

    说明 用于分析redis底层数据结构以及内存情况 底层数据结构分析 1.查看key键的对象类型type key 本地:>sadd test1 本地:>type test1 set 2.查看 ...

  7. Buffering Data

    We keep telling you that you always need to close your files after you're done writing to them. Here ...

  8. 转载 如何理解API,API 是如何工作的

    本文转载于https://blog.csdn.net/cumtdeyurenjie/article/details/80211896 感谢作者 仁杰兄 大家可能最近经常听到 API 这个概念,那什么是 ...

  9. 【leetcode】328. Odd Even Linked List

    题目如下: Given a singly linked list, group all odd nodes together followed by the even nodes. Please no ...

  10. [NOIP模拟16]题解

    A.Blue 出题人大概已经去为国家处理积压子弹了? 贪心,让每一只青蛙(我怂行吧)都尽量往远跳,能到达的最远的被踩了就跳次远的,以此类推.可以维护一个单调队列,表示每只青蛙的位置(开始都是0).然后 ...