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. 整合mybatis时报错:Configuration problem: Unable to locate Spring NamespaceHandler for XML schema namespace [http://www.springframework.org/schema/tx]

    org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Una ...

  2. batch normlization (BN)的讲解

    1. https://zhuanlan.zhihu.com/p/54073204(简单理解) 2. https://zhuanlan.zhihu.com/p/34879333 (有举例说明,但是不太理 ...

  3. shell egrep 引号

    [jg73178@hdcgcgdbsla01dv ~]$ egrep \'SI\' tt.txt 'SI' [jg73178@hdcgcgdbsla01dv ~]$ egrep \"SI\& ...

  4. springmvc Cacheable (RedisTemplate / StringRedisTemplate)

    直接使用spring缓存请见:https://www.cnblogs.com/hanjun0612/p/11661340.html RedisTemplate和StringRedisTemplate配 ...

  5. HTML5 worker计数器简单示例

    效果图: index.html var w; // 开始 function startWorker() { if (typeof (Worker) !== "undefined") ...

  6. 出现Warning: date(): It is not safe to rely on the system's timezone settings的解决办法

    在没有配置,尤其是新安装的PHP中使用date函数时,会报这个错误: Warning: date(): It is not safe to rely on the system's timezone ...

  7. 51nod-1515 明辨是非——并查集

    给n组操作,每组操作形式为x y p. 当p为1时,如果第x变量和第y个变量可以相等,则输出YES,并限制他们相等:否则输出NO,并忽略此次操作. 当p为0时,如果第x变量和第y个变量可以不相等,则输 ...

  8. 百度API获取位置范围内的周边服务

    百度地图API是一套为开发者免费提供的基于百度地图的应用程序接口,包括JavaScript.iOS.Andriod.静态地图.Web服务等多种版本,提供基本地图.位置搜索.周边搜索.... <s ...

  9. asp.net core网关Ocelot的简单介绍& Ocelot集成Identity认证

    文章简介  Ocelot网关简介 Ocelot集成Idnetity认证处理 Ocelot网关简介 Ocelot是一个基于netcore实现的API网关,本质是一组按特定顺序排列的中间件.Ocelot内 ...

  10. Collection Lists

    ArrayList LinkedList  Vector 顺序添加 抽象数据类型(ADT)是一个实现包括储存数据元素的存储结构以及实现基本操作的算法. ArrayList  (1)ArrayList是 ...