【Java多线程】ReentrantReadWriteLock
概述
ReentrantReadWriteLock是Lock的另一种实现方式,ReentrantLock是一个排他锁,同一时间只允许一个线程访问,而ReentrantReadWriteLock允许多个读线程同时访问,但不允许写线程和读线程、写线程和写线程同时访问。相对于排他锁,提高了并发性。在实际应用中,大部分情况下对共享数据(如缓存)的访问都是读操作远多于写操作,这时ReentrantReadWriteLock能够提供比排他锁更好的并发性和吞吐量。
所谓读写锁,是对访问资源共享锁和排斥锁,一般的重入性语义为 如果对资源加了写锁,其他线程无法再获得写锁与读锁,但是持有写锁的线程,可以对资源加读锁(锁降级);如果一个线程对资源加了读锁,其他线程可以继续加读锁。
线程进入读锁的前提条件:
没有其他线程的写锁,
没有写请求或者有写请求,但调用线程和持有锁的线程是同一个。
线程进入写锁的前提条件:
没有其他线程的读锁
没有其他线程的写锁
使用
示例一:利用重入来执行升级缓存后的锁降级

1 class CachedData {
2 Object data;
3 volatile boolean cacheValid; //缓存是否有效
4 ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
5
6 void processCachedData() {
7 rwl.readLock().lock(); //获取读锁
8 //如果缓存无效,更新cache;否则直接使用data
9 if (!cacheValid) {
10 // Must release read lock before acquiring write lock
11 //获取写锁前须释放读锁
12 rwl.readLock().unlock();
13 rwl.writeLock().lock();
14 // Recheck state because another thread might have acquired
15 // write lock and changed state before we did.
16 if (!cacheValid) {
17 data = ...
18 cacheValid = true;
19 }
20 // Downgrade by acquiring read lock before releasing write lock
21 //锁降级,在释放写锁前获取读锁
22 rwl.readLock().lock();
23 rwl.writeLock().unlock(); // Unlock write, still hold read
24 }
25
26 use(data);
27 rwl.readLock().unlock(); //释放读锁
28 }
29 }

示例二:使用 ReentrantReadWriteLock 来提高 Collection 的并发性
通常在 collection 数据很多,读线程访问多于写线程并且 entail 操作的开销高于同步开销时尝试这么做。

1 class RWDictionary {
2 private final Map<String, Data> m = new TreeMap<String, Data>();
3 private final ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
4 private final Lock r = rwl.readLock(); //读锁
5 private final Lock w = rwl.writeLock(); //写锁
6
7 public Data get(String key) {
8 r.lock();
9 try { return m.get(key); }
10 finally { r.unlock(); }
11 }
12 public String[] allKeys() {
13 r.lock();
14 try { return m.keySet().toArray(); }
15 finally { r.unlock(); }
16 }
17 public Data put(String key, Data value) {
18 w.lock();
19 try { return m.put(key, value); }
20 finally { w.unlock(); }
21 }
22 public void clear() {
23 w.lock();
24 try { m.clear(); }
25 finally { w.unlock(); }
26 }
27 }

实现原理
ReentrantReadWriteLock 也是基于AQS实现的,它的自定义同步器(继承AQS)需要在同步状态(一个整型变量state)上维护多个读线程和一个写线程的状态,使得该状态的设计成为读写锁实现的关键。如果在一个整型变量上维护多种状态,就一定需要“按位切割使用”这个变量,读写锁将变量切分成了两个部分,高16位表示读,低16位表示写。
转自:https://www.cnblogs.com/zaizhoumo/p/7782941.html,https://blog.csdn.net/prestigeding/article/details/53286756
【Java多线程】ReentrantReadWriteLock的更多相关文章
- java多线程----ReentrantReadWriteLock
package com.test; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks ...
- Java多线程——ReentrantReadWriteLock源码阅读
之前讲了<AQS源码阅读>和<ReentrantLock源码阅读>,本次将延续阅读下ReentrantReadWriteLock,建议没看过之前两篇文章的,先大概了解下,有些内 ...
- Java多线程系列--“JUC锁”08之 共享锁和ReentrantReadWriteLock
概要 Java的JUC(java.util.concurrent)包中的锁包括"独占锁"和"共享锁".在“Java多线程系列--“JUC锁”02之 互斥锁Ree ...
- Java多线程(五) Lock接口,ReentranctLock,ReentrantReadWriteLock
在JDK5里面,提供了一个Lock接口.该接口通过底层框架的形式为设计更面向对象.可更加细粒度控制线程代码.更灵活控制线程通信提供了基础.实现Lock接口且使用得比较多的是可重入锁(Reentrant ...
- java多线程7:ReentrantReadWriteLock
真实的多线程业务开发中,最常用到的逻辑就是数据的读写,ReentrantLock虽然具有完全互斥排他的效果(即同一时间只有一个线程正在执行lock后面的任务), 这样做虽然保证了实例变量的线程安全性, ...
- 40个Java多线程问题总结
前言 Java多线程分类中写了21篇多线程的文章,21篇文章的内容很多,个人认为,学习,内容越多.越杂的知识,越需要进行深刻的总结,这样才能记忆深刻,将知识变成自己的.这篇文章主要是对多线程的问题进行 ...
- Java多线程系列--“JUC锁”03之 公平锁(一)
概要 本章对“公平锁”的获取锁机制进行介绍(本文的公平锁指的是互斥锁的公平锁),内容包括:基本概念ReentrantLock数据结构参考代码获取公平锁(基于JDK1.7.0_40)一. tryAcqu ...
- Java多线程系列--“JUC锁”04之 公平锁(二)
概要 前面一章,我们学习了“公平锁”获取锁的详细流程:这里,我们再来看看“公平锁”释放锁的过程.内容包括:参考代码释放公平锁(基于JDK1.7.0_40) “公平锁”的获取过程请参考“Java多线程系 ...
- Java多线程系列--“JUC锁”10之 CyclicBarrier原理和示例
概要 本章介绍JUC包中的CyclicBarrier锁.内容包括:CyclicBarrier简介CyclicBarrier数据结构CyclicBarrier源码分析(基于JDK1.7.0_40)Cyc ...
- Java多线程系列--“JUC锁”01之 框架
本章,我们介绍锁的架构:后面的章节将会对它们逐个进行分析介绍.目录如下:01. Java多线程系列--“JUC锁”01之 框架02. Java多线程系列--“JUC锁”02之 互斥锁Reentrant ...
随机推荐
- 高并发连接导致打开文件过多:java.io.IOException: Too many open files 解决方法
用 CentOS 做 API 接口服务器供其他终端调用时,并发量高会报错:java.io.IOException: Too many open files. 其原因是在 Linux 下默认的Socke ...
- SpringBoot之使用Lettuce集成Redis
一.Lettuce Redis这里就不多说,服务端的启动之前的博客里面也有提到,这里略过.Lettuce和Jedis都是连接Redis Server的客户端程序,Jedis在实现上是直连redis s ...
- MySQL基准测试(一)--原因,策略,思路
MySQL基准测试(一)--原因,策略,思路 运用benchmark的原因 验证一些你认为的问题,通过基准测试和模拟数据来验证. 解决生产系统的一些异常 测试系统的当前的运行情况,通过历史的基准测试结 ...
- VUE模仿百度搜索框,按上下方向键及回车键实现搜索选中效果
逻辑介绍: 1.表单获取焦点时,显示搜索建议框 2.输入内容时,请求后台接口,并将返回的数据展示在搜索建议框内 3.表单获取焦点情况下,按键盘上下箭头可实现搜索列表项的切换,按回车可以选择当前激活的选 ...
- 力软开发力软框架力软敏捷开发learun
版本:6.1.6.2 演示地址:www.fishcmonkey.com 联系QQ:6539471
- jsonp请求
发起一个jsonp请求 <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type&q ...
- (2)Microsoft office Word 2013版本操作入门_快速选中
1.快速选中一行 .一段文字: 1.1光标在一行内,双击会选中一个词组.快速点击三下会选中一段, 1.2 鼠标移动到行首,单击击会选中一行,双击选中一段. 1.3 选择全部内容 Ctrl+A , 1 ...
- That Nice Euler Circuit(LA3263+几何)
That Nice Euler Circuit Time Limit:3000MS Memory Limit:0KB 64bit IO Format:%lld & %llu D ...
- 搭建Hbase完全分布式集群
配置HBASE: 因为Hbase要依赖zookeeper集群和Hadoop集群,所以在配置hbase之前先确保已经配置zookeeper集群和Hadoop集群,这里不再详解zookeeper和hado ...
- HDU3987(最小割最少割边)
Harry Potter and the Forbidden Forest Time Limit: 5000/3000 MS (Java/Others) Memory Limit: 65536/ ...