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的使用的更多相关文章

  1. java 可重入读写锁 ReentrantReadWriteLock 详解

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt206 读写锁 ReadWriteLock读写锁维护了一对相关的锁,一个用于只 ...

  2. [图解Java]读写锁ReentrantReadWriteLock

    图解ReentrantReadWriteLock 如果之前使用过读写锁, 那么可以直接看本篇文章. 如果之前未使用过, 那么请配合我的另一篇文章一起看:[源码分析]读写锁ReentrantReadWr ...

  3. Java并发(十):读写锁ReentrantReadWriteLock

    先做总结: 1.为什么用读写锁 ReentrantReadWriteLock? 重入锁ReentrantLock是排他锁,在同一时刻仅有一个线程可以进行访问,但是在大多数场景下,大部分时间都是提供读服 ...

  4. 轻松掌握java读写锁(ReentrantReadWriteLock)的实现原理

    转载:https://blog.csdn.net/yanyan19880509/article/details/52435135 前言 前面介绍了java中排它锁,共享锁的底层实现机制,本篇再进一步, ...

  5. Java并发指南10:Java 读写锁 ReentrantReadWriteLock 源码分析

    Java 读写锁 ReentrantReadWriteLock 源码分析 转自:https://www.javadoop.com/post/reentrant-read-write-lock#toc5 ...

  6. 读写锁ReentrantReadWriteLock:读读共享,读写互斥,写写互斥

    介绍 DK1.5之后,提供了读写锁ReentrantReadWriteLock,读写锁维护了一对锁:一个读锁,一个写锁.通过分离读锁和写锁,使得并发性相比一般的排他锁有了很大提升.在读多写少的情况下, ...

  7. Java并发编程笔记之读写锁 ReentrantReadWriteLock 源码分析

    我们知道在解决线程安全问题上使用 ReentrantLock 就可以,但是 ReentrantLock 是独占锁,同时只有一个线程可以获取该锁,而实际情况下会有写少读多的场景,显然 Reentrant ...

  8. 深入浅出 Java Concurrency (14): 锁机制 part 9 读写锁 (ReentrantReadWriteLock) (2)

      这一节主要是谈谈读写锁的实现. 上一节中提到,ReadWriteLock看起来有两个锁:readLock/writeLock.如果真的是两个锁的话,它们之间又是如何相互影响的呢? 事实上在Reen ...

  9. 深入浅出 Java Concurrency (13): 锁机制 part 8 读写锁 (ReentrantReadWriteLock) (1)

      从这一节开始介绍锁里面的最后一个工具:读写锁(ReadWriteLock). ReentrantLock 实现了标准的互斥操作,也就是一次只能有一个线程持有锁,也即所谓独占锁的概念.前面的章节中一 ...

随机推荐

  1. PSAM 卡的应用 操作方法

    PSAM 卡的应用        PSAM 功能 终端安全存储模块        PASM  常用于 脱机交易的 安全认证        脱机交易的流程          1.卡片对持卡人的认证(防止 ...

  2. SpriteBuilder中pivot关节中的Collide bodies属性

    在SpriteBuilder中,pivot类型的关节表示两个物体围绕一个中心旋转运动的关节,也称之为pin关节. 默认情况下Collide bodies是不选的.因为在大多数情况下你不希望pivot连 ...

  3. linux上 java 使用 javasqlite

    linux上 java 使用 javasqlite http://www.ch-werner.de/javasqlite/ 1) 下载: http://www.ch-werner.de/javasql ...

  4. Unity PUN插件多人在线同步角色坐标旋转角度和动作

    用PUN插件的话,就在OnJoinedRoom()回调函数里,表示加入房间,可以实例化角色,GameObject go=PhotonNetwork.Instantiate(prefabPlayer.n ...

  5. leetCode之旅(12)-反转二叉树

    背景描述 Homebrew 是 OS X 平台上的包管理工具.用其官网的话说就是: the missing package manager for OS X | OS X 平台遗失的包管理器. 相信在 ...

  6. 恶补web之三:http学习

    http是超文本传输协议的简称,该协议设计目的是保证客户机与服务器之间的通信.http的工作方式为客户机与服务器之间的请求-应答协议. 一般来说web浏览器是客户端,计算机上的网络应用程序可能作为服务 ...

  7. Angular v6 正式发布

    Angular 6 正式发布 Angular 6 已经正式发布了!这个主要版本并不关注于底层的框架,更多地关注于工具链,以及使 Angular 在未来更容易快速推进. 作为发布的一部分,我们同步了主要 ...

  8. Java深入了解TreeSet

    Java中的TreeSet是Set的一个子类,TreeSet集合是用来对象元素进行排序的,同样他也可以保证元素的唯一.那TreeSet为什么能保证元素唯一,它是怎样排序的呢?先看一段代码: publi ...

  9. SQL解决时间段重复合并问题

    合并时间段: 将连续或者重叠的时间段合并. create table timesheets ( task_id char(10) not null primary key, startdate dat ...

  10. jquery.js

    /*! jQuery v1.10.2 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license //@ sourceMappingUR ...