java并发之读写锁ReentrantReadWriteLock的使用
Lock比传统线程模型中的synchronized方式更加面向对象,与生活中的锁类似,锁本身也应该是一个对象。两个线程执行的代码片段要实现同步互斥的效果,它们必须用同一个Lock对象。
读写锁:分为读锁和写锁,多个读锁不互斥,读锁与写锁互斥,这是由jvm自己控制的,你只要上好相应的锁即可。如果你的代码只读数据,可以很多人同时读,但不能同时写,那就上读锁;如果你的代码修改数据,只能有一个人在写,且不能同时读取,那就上写锁。总之,读的时候上读锁,写的时候上写锁!
ReentrantReadWriteLock会使用两把锁来解决问题,一个读锁,一个写锁
线程进入读锁的前提条件:
没有其他线程的写锁,
没有写请求或者有写请求,但调用线程和持有锁的线程是同一个
线程进入写锁的前提条件:
没有其他线程的读锁
没有其他线程的写锁
到ReentrantReadWriteLock,首先要做的是与ReentrantLock划清界限。它和后者都是单独的实现,彼此之间没有继承或实现的关系。然后就是总结这个锁机制的特性了:
(a).重入方面其内部的WriteLock可以获取ReadLock,但是反过来ReadLock想要获得WriteLock则永远都不要想。
(b).WriteLock可以降级为ReadLock,顺序是:先获得WriteLock再获得ReadLock,然后释放WriteLock,这时候线程将保持Readlock的持有。反过来ReadLock想要升级为WriteLock则不可能,为什么?参看(a),呵呵.
(c).ReadLock可以被多个线程持有并且在作用时排斥任何的WriteLock,而WriteLock则是完全的互斥。这一特性最为重要,因为对于高读取频率而相对较低写入的数据结构,使用此类锁同步机制则可以提高并发量。
(d).不管是ReadLock还是WriteLock都支持Interrupt,语义与ReentrantLock一致。
(e).WriteLock支持Condition并且与ReentrantLock语义一致,而ReadLock则不能使用Condition,否则抛出UnsupportedOperationException异常。
下面看一个读写锁的例子:
/**
* 模拟数据库表 读数据 写数据
* @author ko
*
*/
public class DataQueue implements Runnable { private int randomNum;// 随机数
private List<String> dataList;// 存放数据的集合
private ReentrantReadWriteLock rwLock;// 读写锁 public DataQueue(int randomNum, List<String> dataList, ReentrantReadWriteLock rwLock) {
super();
this.randomNum = randomNum;
this.dataList = dataList;
this.rwLock = rwLock;
} public void getData(){
rwLock.readLock().lock();// 开启读锁 只能允许读的线程访问
System.out.println("read thread "+Thread.currentThread().getName()+" begin read data");
StringBuffer sb = new StringBuffer();
for (String data : dataList) {
sb.append(data+" ");
}
System.out.println("read thread "+Thread.currentThread().getName()+" read data:"+sb.toString());
System.out.println("read thread "+Thread.currentThread().getName()+" end read data");
rwLock.readLock().unlock();// 释放读锁
} public void setData(){
rwLock.writeLock().lock();// 开启写锁 其它线程不管是读还是写都不能访问
System.out.println("write thread "+Thread.currentThread().getName()+" begin write data");
String data = UUID.randomUUID().toString();
dataList.add(data);
System.out.println("write thread "+Thread.currentThread().getName()+" write data:"+data);
System.out.println("write thread "+Thread.currentThread().getName()+" end write data");
rwLock.writeLock().unlock();// 释放读锁
} @Override
public void run() {
if (randomNum%2 == 0) {
getData();
} else {
setData();
}
}
}
/**
* 利用ReentrantReadWriteLock模拟数据的读写分离
* @author ko
*
*/
public class DatabaseReadWriteSeparation { public static void main(String[] args) {
List<String> dataList = new ArrayList<>();
ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
// DataQueue dataQueue = ;
ExecutorService exec = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
exec.execute(new DataQueue(new Random().nextInt(10), dataList, rwLock));
}
exec.shutdown();
}
}
read thread pool-1-thread-3 begin read data
read thread pool-1-thread-2 begin read data
read thread pool-1-thread-3 read data:
read thread pool-1-thread-2 read data:
read thread pool-1-thread-3 end read data
read thread pool-1-thread-2 end read data
write thread pool-1-thread-1 begin write data
write thread pool-1-thread-1 write data:73a8bfcc-7cb9-4a36-aa06-ecbf90c3e612
write thread pool-1-thread-1 end write data
write thread pool-1-thread-5 begin write data
write thread pool-1-thread-5 write data:c334bb7a-1dfe-4f64-a996-1ba6f714710e
write thread pool-1-thread-5 end write data
read thread pool-1-thread-4 begin read data
read thread pool-1-thread-6 begin read data
read thread pool-1-thread-4 read data:73a8bfcc-7cb9-4a36-aa06-ecbf90c3e612 c334bb7a-1dfe-4f64-a996-1ba6f714710e
read thread pool-1-thread-4 end read data
read thread pool-1-thread-6 read data:73a8bfcc-7cb9-4a36-aa06-ecbf90c3e612 c334bb7a-1dfe-4f64-a996-1ba6f714710e
read thread pool-1-thread-6 end read data
write thread pool-1-thread-7 begin write data
write thread pool-1-thread-7 write data:7266821f-dc72-4a17-8891-6b7ec80a047b
write thread pool-1-thread-7 end write data
write thread pool-1-thread-8 begin write data
write thread pool-1-thread-8 write data:e5fd7de9-3b5c-4a50-8dcb-539d3ca398fd
write thread pool-1-thread-8 end write data
read thread pool-1-thread-10 begin read data
read thread pool-1-thread-10 read data:73a8bfcc-7cb9-4a36-aa06-ecbf90c3e612 c334bb7a-1dfe-4f64-a996-1ba6f714710e 7266821f-dc72-4a17-8891-6b7ec80a047b e5fd7de9-3b5c-4a50-8dcb-539d3ca398fd
read thread pool-1-thread-10 end read data
read thread pool-1-thread-9 begin read data
read thread pool-1-thread-9 read data:73a8bfcc-7cb9-4a36-aa06-ecbf90c3e612 c334bb7a-1dfe-4f64-a996-1ba6f714710e 7266821f-dc72-4a17-8891-6b7ec80a047b e5fd7de9-3b5c-4a50-8dcb-539d3ca398fd
read thread pool-1-thread-9 end read data
从打印的结果可以看出当读的时候线程2 3、4 6、9 10分别是同时两两进行的,写的时候线程5、7、8分别是单独进行的。
java并发之读写锁ReentrantReadWriteLock的使用的更多相关文章
- java 可重入读写锁 ReentrantReadWriteLock 详解
详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt206 读写锁 ReadWriteLock读写锁维护了一对相关的锁,一个用于只 ...
- [图解Java]读写锁ReentrantReadWriteLock
图解ReentrantReadWriteLock 如果之前使用过读写锁, 那么可以直接看本篇文章. 如果之前未使用过, 那么请配合我的另一篇文章一起看:[源码分析]读写锁ReentrantReadWr ...
- Java并发(十):读写锁ReentrantReadWriteLock
先做总结: 1.为什么用读写锁 ReentrantReadWriteLock? 重入锁ReentrantLock是排他锁,在同一时刻仅有一个线程可以进行访问,但是在大多数场景下,大部分时间都是提供读服 ...
- 轻松掌握java读写锁(ReentrantReadWriteLock)的实现原理
转载:https://blog.csdn.net/yanyan19880509/article/details/52435135 前言 前面介绍了java中排它锁,共享锁的底层实现机制,本篇再进一步, ...
- Java并发指南10:Java 读写锁 ReentrantReadWriteLock 源码分析
Java 读写锁 ReentrantReadWriteLock 源码分析 转自:https://www.javadoop.com/post/reentrant-read-write-lock#toc5 ...
- 读写锁ReentrantReadWriteLock:读读共享,读写互斥,写写互斥
介绍 DK1.5之后,提供了读写锁ReentrantReadWriteLock,读写锁维护了一对锁:一个读锁,一个写锁.通过分离读锁和写锁,使得并发性相比一般的排他锁有了很大提升.在读多写少的情况下, ...
- Java并发编程笔记之读写锁 ReentrantReadWriteLock 源码分析
我们知道在解决线程安全问题上使用 ReentrantLock 就可以,但是 ReentrantLock 是独占锁,同时只有一个线程可以获取该锁,而实际情况下会有写少读多的场景,显然 Reentrant ...
- 深入浅出 Java Concurrency (14): 锁机制 part 9 读写锁 (ReentrantReadWriteLock) (2)
这一节主要是谈谈读写锁的实现. 上一节中提到,ReadWriteLock看起来有两个锁:readLock/writeLock.如果真的是两个锁的话,它们之间又是如何相互影响的呢? 事实上在Reen ...
- 深入浅出 Java Concurrency (13): 锁机制 part 8 读写锁 (ReentrantReadWriteLock) (1)
从这一节开始介绍锁里面的最后一个工具:读写锁(ReadWriteLock). ReentrantLock 实现了标准的互斥操作,也就是一次只能有一个线程持有锁,也即所谓独占锁的概念.前面的章节中一 ...
随机推荐
- 查看linux系统是多少位
. getconf LONG_BIT echo $HOSTTYPE uname -a 这三个是对的 我的是64位
- iOSAPP启动效果复杂动画之抽丝剥茧
一.前言 随着开发者的增多和时间的累积,AppStore已经有非常多的应用了,每年都有很多新的APP产生.但是我们手机上留存的应用有限,所以如何吸引用户,成为产品设计的一项重要内容.其中炫酷的动画效果 ...
- Material Design之CollapsingToolbarLayout使用
CollapsingToolbarLayout作用是提供了一个可以折叠的Toolbar,它继承至FrameLayout,给它设置layout_scrollFlags,它可以控制包含在Collapsin ...
- Concurrent包常用方法简介
1 Executor接口 留给开发者自己实现的接口,一般情况下不需要再去实现.它只有一个方法 void execute(Runnable command) 2 ExecutorService接口 它继 ...
- C语言之回文数算法
"回文"是指正读反读都能读通的句子,它是古今中外都有的一种修辞方式和文字游戏,如"我为人人,人人为我"等.在数学中也有这样一类数字有这样的特征,成为回文数(pa ...
- Linux打包命令 - tar
上一篇文章谈到的命令大多仅能针对单一文件来进行压缩,虽然 gzip 与 bzip2 也能够针对目录来进行压缩, 不过,这两个命令对目录的压缩指的是『将目录内的所有文件 "分别" 进 ...
- DB Query Analyzer has been downloaded more than 100,000 times
DB Query Analyzer has been downloaded more than 100,000 times Today I am very ...
- C# PDF Page操作——设置页面切换按钮
概述 在以下示例中,将介绍在PDF文档页面设置页面切换按钮的方法.示例中将页面切换按钮的添加分为了两种情况,一种是设置按钮跳转到首页.下页.上页或者最后一页,另一种是设置按钮跳转到指定页面.两种方法适 ...
- JQuery(一)---- JQ的选择器,属性,节点,样式,函数等操作详解
JQuery的基本概念 JQuery是一个javascript库,JQuery凭借着简洁的语法和跨平台的兼容性,极大的简化了js操作DOM.处理事件.执行动画等操作.JQuery强调的理念是:'wri ...
- 移动web前端开发时注意事项(转)
在智能手机横行的时代,作为一个web前端,不会编写移动web界面,的确是件悲催的事情.当公司准备做一个微信的微网站时,作为一个多年经验的web前端码农,我迷茫了,真心不知道从何下手. 接下来就是搜一堆 ...