ReentrantReadWriteLock的规则是:

多线程情况下:读-写互斥、写-读互斥、写-写互斥、读-读共享

验证“读-写互斥、写-读互斥、写-写互斥、读-读共享”

      //单个线程 读-读 不互斥
r.lock();
r.lock();
System.out.println("读-读 不互斥");
r.unlock();
r.unlock();
//多个线程 读-读 不互斥
new Thread(() -> {
r.lock();
try {Thread.sleep(2000L);} catch (InterruptedException e) {}
r.unlock();
}).start();
new Thread(() -> {
r.lock();
System.out.println("立刻执行");
r.unlock();
}).start();
//单个线程 读-写 互斥,不存在锁升级
r.lock();
w.lock();
System.out.println("ok");
w.unlock();
r.unlock();
//多个线程 写-读 互斥
new Thread(() -> {
w.lock();
try {Thread.sleep(10000000L);} catch (InterruptedException e) {}
w.unlock();
}).start();
try {Thread.sleep(500L);} catch (InterruptedException e) {}//等第一个线程
new Thread(() -> {
r.lock();
System.out.println("我能获得读锁");
r.unlock();
}).start();

ReentrantReadWriteLock使用场景

对于数据比较敏感的场景,

读锁:在读取数据时是不能出现多次读取不一致的情况的,这点有点像可重复读和幻读,

写锁:写数据时,又不能同时读取数据

   private final Map<String, Data> m = new TreeMap<String, Data>();
private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private final Lock r = rwl.readLock();
private final Lock w = rwl.writeLock(); public Data get(String key) {
r.lock();
try { return m.get(key); }
finally { r.unlock(); }
}
public String[] allKeys() {
r.lock();
try { return m.keySet().toArray(); }
finally { r.unlock(); }
}
public Data put(String key, Data value) {
w.lock();
try { return m.put(key, value); }
finally { w.unlock(); }
}
public void clear() {
w.lock();
try { m.clear(); }
finally { w.unlock(); }
}

锁降级

单线程情况下有个特殊的点:读-写不互斥、即降级

 //单个线程 写-读 不互斥,降级
w.lock();
r.lock();
System.out.println("ok");
r.unlock();
w.unlock();
//降级后,其他线程读不能进来 因为写锁并没有完全释放,如果按照下面这种方式做,那么降级将变的没有任何意义,因为你完全可以用一把写锁就代替了
new Thread(() -> {
w.lock();
r.lock();
System.out.println("我已经降级了");
try {Thread.sleep(2000L);} catch (InterruptedException e) {}
r.unlock();
w.unlock();
}).start();
new Thread(() -> {
r.lock();
System.out.println("我能进去");
r.unlock();
}).start();
//正确的姿势如下,这样就能保证在写锁没释放前转化为读锁,写锁紧接着释放,其他线程的读就可以进去了
new Thread(() -> {
w.lock();
r.lock();
w.unlock();
System.out.println("我已经降级了");
try {Thread.sleep(2000L);} catch (InterruptedException e) {}
r.unlock();
}).start();
new Thread(() -> {
r.lock();
System.out.println("我能进去");
r.unlock();
}).start();

锁降级可以帮助我们拿到当前线程修改后的结果而不被其他线程所破坏

锁降级的典型用法

 private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
private final Lock r = rwl.readLock();
private final Lock w = rwl.writeLock(); w.lock();
//writing
r.lock();
w.unlock();
//reading
r.unlock();

ReentrantReadWriteLock的使用的更多相关文章

  1. 【Java并发编程实战】-----“J.U.C”:ReentrantReadWriteLock

    ReentrantLock实现了标准的互斥操作,也就是说在某一时刻只有有一个线程持有锁.ReentrantLock采用这种独占的保守锁直接,在一定程度上减低了吞吐量.在这种情况下任何的"读/ ...

  2. 架构师养成记--14.重入锁ReentrantLock 和 读写锁 ReentrantReadWriteLock

    ReentrantLock 有嗅探锁定和多路分支等功能,其实就是synchronized,wait,notify的升级. this锁定当前对象不方便,于是就有了用new Object()来作为锁的解决 ...

  3. 【JUC】JDK1.8源码分析之ReentrantReadWriteLock(七)

    一.前言 在分析了锁框架的其他类之后,下面进入锁框架中最后一个类ReentrantReadWriteLock的分析,它表示可重入读写锁,ReentrantReadWriteLock中包含了两种锁,读锁 ...

  4. Lock、ReentrantLock、synchronized、ReentrantReadWriteLock使用

    先来看一段代码,实现如下打印效果: 1 2 A 3 4 B 5 6 C 7 8 D 9 10 E 11 12 F 13 14 G 15 16 H 17 18 I 19 20 J 21 22 K 23 ...

  5. Java多线程系列--“JUC锁”08之 共享锁和ReentrantReadWriteLock

    概要 Java的JUC(java.util.concurrent)包中的锁包括"独占锁"和"共享锁".在“Java多线程系列--“JUC锁”02之 互斥锁Ree ...

  6. ReentrantReadWriteLock读写锁详解

    一.读写锁简介 现实中有这样一种场景:对共享资源有读和写的操作,且写操作没有读操作那么频繁.在没有写操作的时候,多个线程同时读一个资源没有任何问题,所以应该允许多个线程同时读取共享资源:但是如果一个线 ...

  7. ReentrantReadWriteLock类和ReentrantLock类的区别

    Java.util.concurrent.locks包定义了两个锁类,ReentrantLock和ReentrantReadWriteLock类. 当有很多线程都从某个数据结构中读取数据而很少有线程对 ...

  8. 多线程之ReentrantReadWriteLock

    java5以后在java.util.concurrent包下,有很多的并发类,可以让我们摆脱java5时,笨重的写法来满足多线程,而且提供了更加丰富的使用场景能力 其中,在locks包下,提供了 Re ...

  9. Java中的显示锁 ReentrantLock 和 ReentrantReadWriteLock

    在Java1.5中引入了两种显示锁,分别是可重入锁ReentrantLock和可重入读写锁ReentrantReadWriteLock.它们分别实现接口Lock和ReadWriteLock.(注意:s ...

  10. java ReentrantReadWriteLock

    // read and write lock is mutual exclusion lock //Listing 7-3. Using ReadWriteLock to Satisfy a Dict ...

随机推荐

  1. c语言指针,数组

    指针:说简单点就是一个地址.例如int *p,p是个变量,里面放的是地址0x0000,同理,每一个指针,不管什么类型,都是地址,也就是空间都是4个字节(32位机). 以此类推,指针也有指向它的指针in ...

  2. 验证控件jQuery Validation Engine调用外部函数验证

    在使用jQuery Validation Engine的时候,我们除了使用自带的API之外,还可以自己自定义正则验证.自定义正则验证上一篇已经讲过了,如果想使用自定义函数进行验证怎么办?其实这个控件有 ...

  3. ROS上利用usb_cam读取摄像头图像

    电脑需要有USB3.0的接口 我使用的环境为:Ubuntu16.04LTS ROS版本是kinetic 一.usb_cam驱动的安装 1.创建ROS工作空间 mkdir -p myros/src cd ...

  4. sql 查找重复数据,并且重复数据有子集

    SELECT A.* FROM comm_department A INNER JOIN ( select path,count(*) as count from comm_department gr ...

  5. layui之layer打开table后分页无效的解决方法

    1.原代码: <body> <div id="showalladdableavms" style="display: none;width:100%&q ...

  6. maven项目跳转页面报空指针错误 Servlet.service() for servlet 异常

    Servlet.service() for servlet jsp threw exceptionjava.lang.NullPointerExceptionat org.jaronsource.ms ...

  7. SPGroup 和SPUser的常用操作

    http://www.cnblogs.com/gzh4455/archive/2012/03/26/2417854.html private bool RemoveUserFromGroup(stri ...

  8. 织梦通过 phpmyadmin 导出的数据,再次导入的时候报错

    错误提示: #1291 – Column 'nature' has duplicated value '婆婆妈妈' in SET SQL 查询: -- -- 导出表中的数据 `dede_member_ ...

  9. GitLab常用命令整理

    进入本地仓库访问位置之后执行命令 1) 远程仓库相关命令 检出仓库:$ git clone git://github.com/jquery/jquery.git 查看远程仓库:$ git remote ...

  10. Linux软件相关记录

    Pidgin+lw-web的聊天记录的文件对应的目录为.purple/logs/webqq/你的QQ号码/,进入之后有选择的删除. mkdir -p 递归创建目录:pwd 显示当前目录:cd .. 回 ...