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 实现了标准的互斥操作,也就是一次只能有一个线程持有锁,也即所谓独占锁的概念.前面的章节中一 ...
随机推荐
- LeetCode之“树”:Sum Root to Leaf Numbers
题目链接 题目要求: Given a binary tree containing digits from 0-9 only, each root-to-leaf path could represe ...
- cocos2d-x升级到3.4与创建android项目
cocos2d-x升级到3.4与创建android项目 1 升级安装cocos2d-x windows7 64位机器, 到官网下载cocos2d-x-3.4: http://www.cocos2d-x ...
- 物理引擎中velocity的单位是个什么鬼?
现在, 你可能对于什么是velocity的单位感到奇怪.他是单位秒中经过点的一个可测量的量(pt/s).如果你想要在iphone横屏从左往右的移动物体,并且你想在1秒内移动1024个点,那么物体的x速 ...
- “《编程珠玑》(第2版)第2章”:B题(向量旋转)
B题是这样子的: 将一个n元一维向量向左旋转(即循环移位)i个位置.例如,当n=8且i=3时,向量abcdefgh旋转为defghabc.简单的代码使用一个n元的中间向量在n步内完成该工作.你能否仅使 ...
- shell脚本里面相互调用时路径不要用pwd获取
shellA调用shellB,如果shellB 里面需要使用路径作为变量,去寻找其它文件.那么要注意,不用pwd,其返回的是系统中用户当前所在位置的路径,也就是shellA的路径,这样就错了.应该用d ...
- ruby读取源代码自身的一种方法
我们知道ruby中如果源代码中一行开头(必须在行的开头)有__END__标示,则表示下面的都是数据行,可以用IO对象DATA来访问这些行.但是如果我们用DATA.rewind一下的话,就可以将文件流指 ...
- javascript简单介绍(二)
晨读单词: onmouseover:鼠标移入 onmouseout:鼠标移出 attribute:属性 node:节点 document:文档 element:元素 textNode:文本节点 app ...
- javascript预览图片——IT轮子系列(九)
再使用htm控件 <input type="file" name="file" /> 上传图片的时候,往往需要先预览图片,然后点击保存按钮,把图片上 ...
- 全局程序集缓存GAC
GAC中的所有的Assembly都会存放在系统目录"%winroot%\assembly下面.放在系统目录下的好处之一是可以让系统管理员通过用户权限来控制Assembly的访问. 目录:C: ...
- ansible常见模块
模块的使用 查看模块帮助 ansible-doc -l 查看所有模块 ansible-doc -s MODULE_NAME 查看指定模块的详细帮助 ansible命令应用基础 语法: ansible ...