多线程系列之七:Read-Write Lock模式
一,Read-Write Lock模式
在Read-Write Lock模式中,读取操作和写入操作是分开考虑的。在执行读取操作之前,线程必须获取用于读取的锁。
在执行写入操作之前,线程必须获取用于写入的锁。所以:
当一个线程在读取时,其他线程可以读取,但是不可以写入。
当一个线程正在写入时,其他线程不可以读取或写入。
因为执行互斥处理会降低程序的性能,但是如果把写入的互斥处理和读取的互斥处理分开来考虑,就可以提高系统性能
二,示例程序
public final class ReadWriteLock {
private int readingReaders = 0;//实际正在读取中的线程个数
private int waitingWriters = 0;//正在等待写入的线程个数
private int writingWriters = 0;//实际正在写入的线程个数
private boolean preferWriter = true;//若写入优先,则为true
public synchronized void readLock()throws InterruptedException{
while (writingWriters > 0 || (preferWriter && waitingWriters > 0)){
wait();
}
readingReaders++;//正在读取的线程个数加1
}
public synchronized void readUnlock(){
readingReaders--;//正在读取的线程个数减1
preferWriter = true;
notifyAll();
}
public synchronized void writeLock()throws InterruptedException{
waitingWriters++;//等待写入的线程加1
try {
while (readingReaders > 0 || writingWriters > 0){
wait();
}
}finally {
waitingWriters--;//等待写入的线程减1
}
writingWriters++;//正在写入的线程加1
}
public synchronized void writeUnlock(){
writingWriters--;//正在写入的线程减1
preferWriter = false;
notifyAll();
}
}
public class Data {
private final char[] buffer;
public final ReadWriteLock lock = new ReadWriteLock();
public Data(int size){
this.buffer = new char[size];
for (int i = 0; i < buffer.length; i++) {
buffer[i] = '*';
}
}
public char[] read()throws InterruptedException{
lock.readLock();
try {
return doRead();
}finally {
lock.readUnlock();
}
}
/**
* 实际的读取操作,创建一个新的char数组newbuf,来复制buffer里的内容,并返回newbuf
* @return
*/
private char[] doRead(){
char[] newbuf = new char[buffer.length];
for (int i = 0; i < buffer.length; i++) {
newbuf[i] = buffer[i];
}
slowly();
return newbuf;
}
public void write(char c)throws InterruptedException{
lock.writeLock();
try {
doWrite(c);
}finally {
lock.writeUnlock();
}
}
/**
* 实际的写入操作,每读取一个字符,就执行一次耗时操作。写入操作时间比读取操作时间长
* @param c
*/
public void doWrite(char c){
for (int i = 0; i < buffer.length; i++) {
buffer[i] = c;
slowly();
}
}
/**
* 耗时操作,模拟处理业务逻辑
*/
public void slowly(){
try {
Thread.sleep(50);
}catch (InterruptedException e){
}
}
}
public class ReaderThread extends Thread {
private final Data data;
public ReaderThread(Data data){
this.data = data;
}
@Override
public void run() {
try {
while (true){
char[] readbuf = data.read();
System.out.println(Thread.currentThread().getName()+" reads "+
String.valueOf(readbuf));
}
}catch (InterruptedException e){
}
}
}
public class WriterThread extends Thread {
private static final Random random = new Random();
private final Data data;
private final String filler;
private int index = 0;
public WriterThread(Data data,String filler){
this.data = data;
this.filler = filler;
}
@Override
public void run() {
try {
while (true){
char c = nextchar();
data.write(c);
Thread.sleep(random.nextInt(3000));
}
}catch (InterruptedException e){
}
}
private char nextchar(){
char c = filler.charAt(index);
index++;
if (index >= filler.length()){
index = 0;
}
return c;
}
}
public class Test {
public static void main(String[] args) {
Data data = new Data(10);
for (int i = 0; i < 6; i++) {
new ReaderThread(data).start();
}
new WriterThread(data,"ABCDEFGHIJKLMNOPQRSTUVWXYZ").start();
new WriterThread(data,"abcdefghijklmnopqrstuvwxyz").start();
}
}
三,适用场景
1.读取操作频繁
2.读取频率比写入频率高
四,锁的含义
1.synchronized可以用于获取实例的锁,Java的每一个实例都持有一个锁,但同一个锁不能被两个以上的线程同时获取,
这种结构是Java编程规范规定的,java虚拟机也是这样实现的。这就是java提供的物理锁。
2.本章的 用于读取的锁 和 用于写入的锁,是开发人员自己实现的一种结构。这种锁是逻辑锁,我们可以通过修改ReadWriteLock类来改变锁的运行
ReadWriteLock类提供了用于 读取的锁 和 用于写入的锁 的这两个逻辑锁。但是用于实现这两个逻辑锁的物理锁只有一个,就是ReadWriteLock实例持有的锁
五,java.util.concurrent.locks.ReadWriteLock
java并发包提供了读写锁。
public class Data {
private final char[] buffer;
private final ReadWriteLock lock = new ReentrantReadWriteLock(true);
private final Lock readLock = lock.readLock();
private final Lock writeLock = lock.writeLock();
public Data(int size){
this.buffer = new char[size];
for (int i = 0; i < buffer.length; i++) {
buffer[i] = '*';
}
}
public char[] read()throws InterruptedException{
readLock.lock();
try {
return doRead();
}finally {
readLock.unlock();
}
}
/**
* 实际的读取操作,创建一个新的char数组newbuf,来复制buffer里的内容,并返回newbuf
* @return
*/
private char[] doRead(){
char[] newbuf = new char[buffer.length];
for (int i = 0; i < buffer.length; i++) {
newbuf[i] = buffer[i];
}
slowly();
return newbuf;
}
public void write(char c)throws InterruptedException{
writeLock.lock();
try {
doWrite(c);
}finally {
writeLock.unlock();
}
}
/**
* 实际的写入操作,每读取一个字符,就执行一次耗时操作。写入操作时间比读取操作时间长
* @param c
*/
public void doWrite(char c){
for (int i = 0; i < buffer.length; i++) {
buffer[i] = c;
slowly();
}
}
/**
* 耗时操作,模拟处理业务逻辑
*/
public void slowly(){
try {
Thread.sleep(50);
}catch (InterruptedException e){
}
}
}
多线程系列之七:Read-Write Lock模式的更多相关文章
- java多线程系列15 设计模式 生产者 - 消费者模式
生产者-消费者 生产者消费者模式是一个非常经典的多线程模式,比如我们用到的Mq就是其中一种具体实现 在该模式中 通常会有2类线程,消费者线程和生产者线程 生产者提交用户请求 消费者负责处理生产者提交的 ...
- 多线程系列之十:Future模式
一,Future模式 假设有一个方法需要花费很长的时间才能获取运行结果.那么,与其一直等待结果,不如先拿一张 提货单.获取提货单并不耗费时间.这里提货单就称为Future角色获取Future角色的线程 ...
- 多线程系列之四:Guarded Suspension 模式
一,什么是Guarded Suspension模式如果执行现在的处理会造成问题,就让执行处理的线程等待.这种模式通过让线程等待来保证实例的安全性 二,实现一个简单的线程间通信的例子 一个线程(Clie ...
- java多线程系列 目录
Java多线程系列1 线程创建以及状态切换 Java多线程系列2 线程常见方法介绍 Java多线程系列3 synchronized 关键词 Java多线程系列4 线程交互(wait和 ...
- java多线程系列(四)---Lock的使用
Lock的使用 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我的理 ...
- 多线程设计模式——Read-Write Lock模式和Future模式分析
目录 多线程程序评价标准 任何模式都有一个相同的"中心思想" Read-Write Lock 模式 RW-Lock模式特点 冲突总结 手搓RW Lock模式代码 类图 Data类 ...
- java多线程系列(三)---等待通知机制
等待通知机制 前言:本系列将从零开始讲解java多线程相关的技术,内容参考于<java多线程核心技术>与<java并发编程实战>等相关资料,希望站在巨人的肩膀上,再通过我的理解 ...
- Java多线程系列——原子类的实现(CAS算法)
1.什么是CAS? CAS:Compare and Swap,即比较再交换. jdk5增加了并发包java.util.concurrent.*,其下面的类使用CAS算法实现了区别于synchronou ...
- Java多线程系列--“JUC锁”03之 公平锁(一)
概要 本章对“公平锁”的获取锁机制进行介绍(本文的公平锁指的是互斥锁的公平锁),内容包括:基本概念ReentrantLock数据结构参考代码获取公平锁(基于JDK1.7.0_40)一. tryAcqu ...
随机推荐
- Window快捷键
1.带windows 键 Win + E 打开文件夹 Win + R 调出运行命令 Win + T 显示任务栏,并在在其中切换 Win +Pause 显示系统属性 Win + Home 最小化 / 还 ...
- JQuery Plugin 开发
学习 JQuery 插件开发之后, 可以将自己平时常用的功能封装成插件, 便于在不同的项目之间使用. JQuery 官网上的 插件开发教程就很不错, 简单易懂. 参考网址: http://learn. ...
- java操作elasticsearch实现聚合查询
1.max 最大值 //max 求最大值 @Test public void test30() throws UnknownHostException{ //1.指定es集群 cluster.name ...
- python collection模块
一.模块的认识 定义:模块就是我们把装有特定功能的代码进行归类的结果. 说明:从代码编写的单位来看我们的城西,从小到大:一条代码 -> 语句块 - >代码块(函数.类)-> 模块. ...
- 【车】汽车X40保养
参考文档: [养车成本]小保养331元,奔腾X40养车成本调查
- Git无法提交,报错
Failed at the ant-design-pro@2.2.1 lint-staged script. npm ERR! This is probably not a problem with ...
- css样式的书写顺序及原理
刚开始学习前端的时候,每次写css样式都是用到什么就在样式表后添加什么,完全没有考虑到样式属性的书写顺序对网页加载代码的影响.后来逐渐才知道正确的样式顺序不仅易于查看,并且也属于css样式优化的一种方 ...
- 【js】把一个json对象转成想要的数组
var arrTemp = []; var arrRes = []; var jsonObjct = { "CRM_UNIT_TYPE_A": { "dic_desc&q ...
- rabbitMQ常用方法说明 – 6中工作模式及关键点
首先,RabbitMQ解决什么问题? 1)信息的发送者和接收者如何维持连接,如果一方的连接中断,这期间的数据如何防止丢失? 2)如何降低发送者和接收者的耦合度? 3)如何让Priority高的接收者先 ...
- TypeError: Buffer.alloc is not a function
错误信息:TypeError: Buffer.alloc is not a function 截图如下: 解决办法(依次从上往下执行): sudo npm cache clean -f sudo np ...