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. 关于KiCAD的一些插件

    关于KiCAD的一些插件 https://gitee.com/KiCAD-CN/KiCad-CN-Forum/blob/master/KiCad_help_zh_CN.md#swapit-%E5%B7 ...

  2. C# Copy一个文件到另一个文件夹下

    public static void CopyToFile() { //源文件路径 string sourceName = @"D:\Source\Test.txt"; //目标路 ...

  3. 【JS学习】慕课网9-14 删除结点操作的问题

    试一试,定义clearText()函数,完成节点内容的删除. 1. 删除该节点的内容,先要获取子节点. 2. 然后使用循环遍历每个子节点. 3. 使用removeChild()删除节点. 特别要注意的 ...

  4. linux netstat 统计连接数查看外部(转)

    转自:http://boy-liguang.blog.sohu.com/187052443.html linux netstat 统计连接数查看外部 2011-10-11 08:52阅读(16333) ...

  5. Qt Creator 无法解析的外部符号(转)

    https://blog.csdn.net/yvhvv/article/details/8474356 一直报某个构造函数无法解析,但看了下代码中没有问题,后来把debug文件夹删掉,重新运行后问题解 ...

  6. codeforces 1B 模拟

    题目大意: 给出两种行列位置的表示方法,一个是Excel表示法,一个是(R,C)坐标表示.给出一种表示,输出另外一种表示. 基本思路: 模拟,首先判断是哪一种表示法,然后转换成另外一种表示方法: 我做 ...

  7. 分布式锁实现(一):Redis

    前言 单机环境下我们可以通过JAVA的Synchronized和Lock来实现进程内部的锁,但是随着分布式应用和集群环境的出现,系统资源的竞争从单进程多线程的竞争变成了多进程的竞争,这时候就需要分布式 ...

  8. 源码方式安装 lrzsz库

    源码方式安装 lrzsz库:https://www.cnblogs.com/cocoajin/p/11731787.html 我们都知道安装了lrzsz工具的linux系统环境,在shell里可以非常 ...

  9. Minimum Snap轨迹规划详解(2)corridor与时间分配

    在上一篇文章中,我们得到的轨迹并不是很好,与路径差别有点大,我们期望规划出的轨迹跟路径大致重合,而且不希望有打结的现象,而且希望轨迹中的速度和加速度不超过最大限幅值.为了解决这些问题有两种思路: 思路 ...

  10. HIve分组查询返回每组的一条记录

    select a.lng,a.lat from (select row_number() over ( partition by uid,grid_id) as rnum,weighted_centr ...