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 实现了标准的互斥操作,也就是一次只能有一个线程持有锁,也即所谓独占锁的概念.前面的章节中一 ...
随机推荐
- OM模块功能&API详解
(一)销售订单概述 1.1 与车间模块关系 当使用ATO类型订单时,订单管理模块会直接在车间模块中产生任务 1.2 与库存模块关系 在销售订单中使用的物料,单位等信息均来自库存模块,在订单执行 ...
- 【一天一道LeetCode】#328 Odd Even Linked List
一天一道LeetCode系列 (一)题目 Given a singly linked list, group all odd nodes together followed by the even n ...
- OpenCV问题集锦,图片显示不出来,WaitKey(0),imread()不能读图片,未经处理的异常,等问题集合
昨天根据uc伯克利的人工图像分割文件.seg,显示图像的时候调用了OpenCV的库函数,图片都能用imwrite写好,但是imshow死活显示不出来. 今天早上发现原来是imshow()后面应该加上: ...
- 面试之路(29)-TCP流量控制和拥塞控制-滑动窗口协议详解
拥塞: 拥塞发生的主要原因在于网络能够提供的资源不足以满足用户的需求,这些资源包括缓存空间.链路带宽容量和中间节点的处理能力.由于互联网的设计机制导致其缺乏"接纳控制"能力,因此在 ...
- 如何通过jQuery获取一个没有定高度的元素---------的自适应高度(offsetHeight的正确使用方法)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- myBatis之入门示例
1. myBatis目录结构: --src ---entity [POJO类] ---mappers [映射类] ----*Mapper.java [方法接口,相当于Dao] ----*Mapper. ...
- sublime使用技巧之集成VI
熟悉开发工具,减少多余的操作流程有助于提高开发效率,而Sublime Text 2是sublime产品的经典版本,因此本文基于Sublime Text 2讲解sublime的使用技巧. VI的主要作用 ...
- Android Studio 2.3 instant run与miui冲突问题的解决
Android Studio最近发布的2.3版本,由于这个版本改进后的Instant Run功能和很多国内ROM存在兼容问题,所以导致不得不做一些妥协策略,具体在小米Rom上,就是把小米rom的调试定 ...
- “Location of the Android SDK has not been set up in the preferences”问题的解决
方法来源:http://stackoverflow.com/questions/5894929/location-of-the-Android-sdk-has-not-been-setup-in-th ...
- PHP基础(一)--字符串函数大盘点(基础篇)
参考地址http://php.net/manual/zh/ref.strings.php addcslashes - 以 C 语言风格使用反斜线转义字符串中的字符 string addcslas ...