注 :本文应结合【天勤笔记】进行学习。

1.读者优先

设置rmutex信号量来对readcount变量进行互斥访问、mutex信号量对写者与读者进行同步。

     static syn rmutex=new syn(1);//多个【读者】对readcount进行【互斥】访问
static syn mutex=new syn(1);//多个【写者】对数据区进行【互斥】访问

java代码:(点击加号可查看)

 package 读者优先;
import java.util.Scanner; public class Main { public static void main(String[] args) {
System.out.print("请设置读者数目:");
Scanner scan=new Scanner(System.in);
int readNum =scan.nextInt(); System.out.print("请设置写者数目:");
scan=new Scanner(System.in);
int writeNum =scan.nextInt(); System.out.print("请设置循环上限:");
scan=new Scanner(System.in);
Global.UpBound =scan.nextInt(); scan.close(); Reader r[]=new Reader[readNum];
Writer w[]=new Writer[writeNum];
int i;
for(i=0;i<readNum;i++){
r[i]=new Reader(i+1);
}
for(i=0;i<writeNum;i++){
w[i]=new Writer(i+1);
}
Thread []r_t=new Thread[readNum];
Thread []w_t=new Thread[writeNum];
for(i=0;i<readNum;i++){
r_t[i]=new Thread(r[i]);
}
for(i=0;i<writeNum;i++){
w_t[i]=new Thread(w[i]);
}
for(i=0;i<writeNum;i++){
w_t[i].start();
}
for(i=0;i<readNum;i++){
r_t[i].start();
} } } class syn{//PV操作类
int count=0;//信号量
syn(){}
syn(int a){count=a;}
public synchronized void Wait(){ //关键字 synchronized 保证了此操作是一条【原语】
count--;
if(count<0){//等于0 :有一个进程进入了临界区
try { //小于0:abs(count)=阻塞的进程数目
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void Signal(){ //关键字 synchronized 保证了此操作是一条【原语】
count++;
if(count<=0){//如果有进程阻塞
this.notify();//All
}
}
} class Global{
static syn rmutex=new syn(1);//多个【读者】对readcount进行【互斥】访问
static syn mutex=new syn(1);//多个【写者】对数据区进行【互斥】访问
static int dataZone=0; //数据区
static int readcount=0; //用于记录读者的数量
static int data=0;
static int UpBound=20;
} class Reader implements Runnable{//读者
int ID=0;
Reader(){}
Reader(int id){ID=id;}
public void run(){
while(Global.data<=Global.UpBound){
//对readcount进行操作
Global.rmutex.Wait();
if(Global.readcount==0){//这是第一个读者,应该阻止写者的进入
Global.mutex.Wait();
}
Global.readcount++;//读者数量增减
Global.rmutex.Signal();
//对readcount操作结束 /*
* 进行读操作
*/
int readData=Global.dataZone;
System.out.println("读者"+ID+"读出了数据:"+readData);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
/*
* 结束读操作
*/ //对readcount进行操作
Global.rmutex.Wait();
Global.readcount--;//读者数量减少
if(Global.readcount==0){//这是最后一个读者,唤醒写者
Global.mutex.Signal();
}
Global.rmutex.Signal();
//对readcount操作结束
}
}
} class Writer implements Runnable{//写者
int ID=0;
Writer(){}
Writer(int id){ID=id;}
public void run(){
while(Global.data<=Global.UpBound){
Global.mutex.Wait(); //申请对数据区进行访问
/*
* 进行写操作
*/
Global.data++;
int writeData=Global.data;
System.out.println("写者"+ID+"写入了数据:"+writeData);
Global.dataZone=Global.data;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
/*
* 结束写操作
*/
Global.mutex.Signal(); //释放数据区,允许其他进程读写
}
}
}

2.公平策略

在这里,增加wmutex信号量来表示是否有正在进行或等待的写者

 static syn wmutex=new syn(1);//表示是否存在【进行】或【等待】的【写者】

读者readcount进入区和离开区增加wait(wmutex)signal(wmutex)的操作:

写者的进入区与离开区增加wait(wmutex)signal(wmutex)的操作:

java代码:(点击加号可查看)

 package 公平策略;

 import java.util.Scanner;

 public class Main {

     public static void main(String[] args) {
System.out.print("请设置读者数目:");
Scanner scan=new Scanner(System.in);
int readNum =scan.nextInt(); System.out.print("请设置写者数目:");
scan=new Scanner(System.in);
int writeNum =scan.nextInt(); System.out.print("请设置循环上限:");
scan=new Scanner(System.in);
Global.UpBound =scan.nextInt(); scan.close(); Reader r[]=new Reader[readNum];
Writer w[]=new Writer[writeNum];
int i;
for(i=0;i<readNum;i++){
r[i]=new Reader(i+1);
}
for(i=0;i<writeNum;i++){
w[i]=new Writer(i+1);
}
Thread []r_t=new Thread[readNum];
Thread []w_t=new Thread[writeNum];
for(i=0;i<readNum;i++){
r_t[i]=new Thread(r[i]);
}
for(i=0;i<writeNum;i++){
w_t[i]=new Thread(w[i]);
}
for(i=0;i<writeNum;i++){
w_t[i].start();
}
for(i=0;i<readNum;i++){
r_t[i].start();
} } } class syn{//PV操作类
int count=0;//信号量
syn(){}
syn(int a){count=a;}
public synchronized void Wait(){ //关键字 synchronized 保证了此操作是一条【原语】
count--;
if(count<0){//等于0 :有一个进程进入了临界区
try { //小于0:abs(count)=阻塞的进程数目
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void Signal(){ //关键字 synchronized 保证了此操作是一条【原语】
count++;
if(count<=0){//如果有进程阻塞
this.notify();//All
}
}
} class Global{
static syn rmutex=new syn(1);//多个【读者】对readcount进行【互斥】访问
static syn mutex=new syn(1);//多个【写者】对数据区进行【互斥】访问
static int dataZone=0; //数据区
static int readcount=0; //用于记录读者的数量
static int data=0;
static int UpBound=20;
static syn wmutex=new syn(1);//表示是否存在【进行】或【等待】的【写者】
} class Reader implements Runnable{//读者
int ID=0;
Reader(){}
Reader(int id){ID=id;}
public void run(){
while(Global.data<=Global.UpBound){
Global.wmutex.Wait();//检测是否存在写者,无写者才能进入 //对readcount进行操作
Global.rmutex.Wait();
if(Global.readcount==0){//这是第一个读者,应该阻止写者的进入
Global.mutex.Wait();
}
Global.readcount++;//读者数量增减
Global.rmutex.Signal();
//对readcount操作结束 Global.wmutex.Signal();//恢复wmutex /*
* 进行读操作
*/
int readData=Global.dataZone;
System.out.println("读者"+ID+"读出了数据:"+readData);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
/*
* 结束读操作
*/ //对readcount进行操作
Global.rmutex.Wait();
Global.readcount--;//读者数量减少
if(Global.readcount==0){//这是最后一个读者,唤醒写者
Global.mutex.Signal();
}
Global.rmutex.Signal();
//对readcount操作结束 }
}
} class Writer implements Runnable{//写者
int ID=0;
Writer(){}
Writer(int id){ID=id;}
public void run(){
while(Global.data<=Global.UpBound){
Global.wmutex.Wait();
Global.mutex.Wait(); //申请对数据区进行访问
/*
* 进行写操作
*/
Global.data++;
int writeData=Global.data;
System.out.println("写者"+ID+"写入了数据:"+writeData);
Global.dataZone=Global.data;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
/*
* 结束写操作
*/
Global.mutex.Signal(); //释放数据区,允许其他进程读写
Global.wmutex.Signal();
}
}
}

3.写者优先

 公平策略是在读者优先的基础上进行修改,写者优先也是在公平策略的基础上进行修改。

在这里,我们增加了readable信号量,writecount全局变量。

在读者中,用readable代替了【公平策略】中的wmutex来对等待队列中的写者进行标记:

在写者中,通过判断等待队列中是否有写者,来控制读者的进入,并用wmutex对writecount全局变量进行互斥访问:

java代码:(点击加号可查看)

 package 写者优先;

 import java.util.Scanner;

 public class Main {

     public static void main(String[] args) {
System.out.print("请设置读者数目:");
Scanner scan=new Scanner(System.in);
int readNum =scan.nextInt(); System.out.print("请设置写者数目:");
scan=new Scanner(System.in);
int writeNum =scan.nextInt(); System.out.print("请设置循环上限:");
scan=new Scanner(System.in);
Global.UpBound =scan.nextInt(); scan.close(); Reader r[]=new Reader[readNum];
Writer w[]=new Writer[writeNum];
int i;
for(i=0;i<readNum;i++){
r[i]=new Reader(i+1);
}
for(i=0;i<writeNum;i++){
w[i]=new Writer(i+1);
}
Thread []r_t=new Thread[readNum];
Thread []w_t=new Thread[writeNum];
for(i=0;i<readNum;i++){
r_t[i]=new Thread(r[i]);
}
for(i=0;i<writeNum;i++){
w_t[i]=new Thread(w[i]);
}
for(i=0;i<writeNum;i++){
w_t[i].start();
}
for(i=0;i<readNum;i++){
r_t[i].start();
} } } class syn{//PV操作类
int count=0;//信号量
syn(){}
syn(int a){count=a;}
public synchronized void Wait(){ //关键字 synchronized 保证了此操作是一条【原语】
count--;
if(count<0){//等于0 :有一个进程进入了临界区
try { //小于0:abs(count)=阻塞的进程数目
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void Signal(){ //关键字 synchronized 保证了此操作是一条【原语】
count++;
if(count<=0){//如果有进程阻塞
this.notify();//All
}
}
} class Global{
static syn mutex=new syn(1);//控制互斥访问的数据区
static syn rmutex=new syn(1);//多个【读者】对readcount进行【互斥】访问
static syn wmutex=new syn(1);//多个【写者】对writecount进行【互斥】访问
static syn readable=new syn(1);//表示当前是否有写者 static int dataZone=0; //数据区
static int readcount=0; //用于记录读者的数量
static int writecount=0; //用于记录读者的数量 static int data=0;
static int UpBound=20; } class Reader implements Runnable{//读者
int ID=0;
Reader(){}
Reader(int id){ID=id;}
public void run(){
while(Global.data<=Global.UpBound){
Global.readable.Wait();//检测是否存在写者,无写者才能进入 //对readcount进行操作
Global.rmutex.Wait();
if(Global.readcount==0){//这是第一个读者,应该阻止写者的进入
Global.mutex.Wait();
}
Global.readcount++;//读者数量增减
Global.rmutex.Signal();
//对readcount操作结束 Global.readable.Signal();//恢复readable /*
* 进行读操作
*/
int readData=Global.dataZone;
System.out.println("读者"+ID+"读出了数据:"+readData);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
/*
* 结束读操作
*/ //对readcount进行操作
Global.rmutex.Wait();
Global.readcount--;//读者数量减少
if(Global.readcount==0){//这是最后一个读者,唤醒写者
Global.mutex.Signal();
}
Global.rmutex.Signal();
//对readcount操作结束
}
}
} class Writer implements Runnable{//写者
int ID=0;
Writer(){}
Writer(int id){ID=id;}
public void run(){
while(Global.data<=Global.UpBound){
Global.wmutex.Wait();//准备修改writecount
if(Global.writecount==0) Global.readable.Wait();//如果是第一个读者,则阻止后续读者进入
Global.writecount++;
Global.wmutex.Signal();//结束对writecount的修改 Global.mutex.Wait(); //申请对数据区进行访问
/*
* 进行写操作
*/
Global.data++;
int writeData=Global.data;
System.out.println("写者"+ID+"写入了数据:"+writeData);
Global.dataZone=Global.data;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
/*
* 结束写操作
*/
Global.mutex.Signal(); //释放数据区,允许其他进程读写 Global.wmutex.Wait();//准备修改writecount
Global.writecount--;
if(Global.writecount==0) Global.readable.Signal();//如果是最后一个写者,唤醒读者
Global.wmutex.Signal();//结束对writecount的修改
}
}
}

4.三种情况下运行结果的对比

在同一组测试数据下,三种情况的运行结果见上图。左为读者优先,中为公平策略,右为写者优先。可见左图读者进行了大量的插队操作,中图的读者与写者都是交替进行的,右图的写者从一开始就在插队。

Java实现PV操作 | 读者与写者(在三种情况下进行讨论)的更多相关文章

  1. Java实现PV操作 | 生产者与消费者

    导语 在学习操作系统的过程中,PV操作是很重要的一个环节.然而面对书本上枯燥的代码,每一个爱好技术的人总是想能亲自去实现.现在我要推出一个专题,专门讲述如何用Java实现PV操作,让操作系统背后的逻辑 ...

  2. JAVA写JSON的三种方法,java对象转json数据

    JAVA写JSON的三种方法,java对象转json数据 转自:http://www.xdx97.com/#/single?bid=5afe2ff9-8cd1-67cf-e7bc-437b74c07a ...

  3. Node.js写文件的三种方法

    Node.js写文件的三种方式: 1.通过管道流写文件 采用管道传输二进制流,可以实现自动管理流,可写流不必当心可读流流的过快而崩溃,适合大小文件传输(推荐) var readStream = fs. ...

  4. java用POI操作excel——随便写一下,最基础的东西

    前两天部门实施在做一个东西,需要把客户放在Excel中的数据导入到Oracle数据库中,我就想着直接写一个模板,必要的时候改一下实体类应该可以解放实施同事的双手,不过在实际写的过程中,还是碰到很多问题 ...

  5. Java实现PV操作 | 哲学家进餐问题

    运行结果: Java代码: public class Main { public static void main(String[] args) { Global global=new Global( ...

  6. Java中OutOfMemoryError(内存溢出)的三种情况及解决办法

    转载自:http://blog.sina.com.cn/s/blog_701c951f0100n1sp.html 相信有一定java开发经验的人或多或少都会遇到OutOfMemoryError的问题, ...

  7. python面对对象编程------3:写集合类的三种方法

    写一个集合类的三种方法:wrap,extend,invent 一:包装一个集合类 class Deck: def __init__( self ): self._cards = [card6(r+1, ...

  8. java代码中init method和destroy method的三种使用方式

    在java的实际开发过程中,我们可能常常需要使用到init method和destroy method,比如初始化一个对象(bean)后立即初始化(加载)一些数据,在销毁一个对象之前进行垃圾回收等等. ...

  9. Java中数组转为List三种情况的优劣对比,常犯的类型转换错误原因解析

    一.最常见方式(未必最佳)通过 Arrays.asList(strArray) 方式,将数组转换List后,不能对List增删,只能查改,否则抛异常. 关键代码:List list = Arrays. ...

随机推荐

  1. SQL Server的常用提示

    在SQL Server中,有许多SQL语句的提示,本文总结一些比较常用的提示. OPTION LOOP/MERGE/HASH JOIN提示 该提示可以改变整个SQL语句中所有JOIN的关联算法,所以请 ...

  2. lazyload的使用方法

    http://blog.csdn.net/peidandan/article/details/8107634

  3. 树莓派安装使用docker

    2019/11/11, 树莓派4B, Raspbian Buster,Docker 19.03.4 摘要:树莓派Raspbian Buster中安装Docker,Dockerfile更改软件源 安装d ...

  4. tf.random_shuffle()函数解析

    tf.random_shuffle(value, seed=None, name=None) 函数就是随机地将张量沿第一维度打乱 value:将被打乱的张量. seed:一个 Python 整数.用于 ...

  5. python自动备份阿里云数据库binlog

    #coding:utf8from aliyunsdkcore import clientfrom aliyunsdkrds.request.v20140815 import DescribeBacku ...

  6. 深圳宝安图书馆官网错误 HTTP Status 500 - Servlet.init() for servlet spring threw exception

    停留了一段时间没有动 打开https://www.balib.cn/balib/category/152 *********************************************** ...

  7. Windows中常用工具

    护眼软件 f.lux https://justgetflux.com/ Typora https://www.typora.io/ Markdown工具,小巧,方便. Snipaste https:/ ...

  8. 封装axios,带请求头和响应头

    import axios from "axios"; import qs from "qs"; //处理参数 import router from '../ro ...

  9. 英语partschinite芬达石partschinite锰铝榴石

    partschinite指锰铝榴石,属于石榴石的一种,由于它有芬达饮料的诱人颜色,大家也称其为“芬达石”.石榴石宝石族中重要品种之一,化学成分为锰铝硅酸盐,颜色从红到橙红,红到棕红,玫瑰红.浅玫红均有 ...

  10. 【案例】保健品行业如何优化供应链管理?APS系统来帮忙

    仙乐健康一直致力于为了客户提供世界级的产品及服务,随着业务量的不断扩大,公司先后实施了ERP系统,CRM系统,WMS系统,OA系统,朝着行业信息化水平领先的目标迈进. 但近年仅仅拥有传统ERP系统和手 ...