zoukankan      html  css  js  c++  java
  • Java实现PV操作 | 读者与写者(在三种情况下进行讨论)

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

    1.读者优先

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

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

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

      1 package 读者优先;
      2 import java.util.Scanner;
      3 
      4 public class Main {
      5 
      6     public static void main(String[] args) {
      7         System.out.print("请设置读者数目:");
      8         Scanner scan=new Scanner(System.in);
      9         int readNum =scan.nextInt();
     10         
     11         System.out.print("请设置写者数目:");
     12         scan=new Scanner(System.in);
     13         int writeNum =scan.nextInt();        
     14         
     15         System.out.print("请设置循环上限:");
     16         scan=new Scanner(System.in);
     17         Global.UpBound =scan.nextInt();
     18         
     19         scan.close();
     20 
     21         
     22         Reader r[]=new Reader[readNum];
     23         Writer w[]=new Writer[writeNum];
     24         int i;
     25         for(i=0;i<readNum;i++){
     26             r[i]=new Reader(i+1);
     27         }
     28         for(i=0;i<writeNum;i++){
     29             w[i]=new Writer(i+1);
     30         }
     31         Thread []r_t=new Thread[readNum];
     32         Thread []w_t=new Thread[writeNum];
     33         for(i=0;i<readNum;i++){
     34             r_t[i]=new Thread(r[i]);
     35         }        
     36         for(i=0;i<writeNum;i++){
     37             w_t[i]=new Thread(w[i]);
     38         }
     39         for(i=0;i<writeNum;i++){
     40             w_t[i].start();
     41         }    
     42         for(i=0;i<readNum;i++){
     43             r_t[i].start();
     44         }    
     45         
     46 
     47     
     48     }
     49 
     50 }
     51 
     52 class syn{//PV操作类
     53     int count=0;//信号量
     54     syn(){}
     55     syn(int a){count=a;}
     56     public synchronized void Wait(){ //关键字 synchronized 保证了此操作是一条【原语】
     57         count--;
     58         if(count<0){//等于0 :有一个进程进入了临界区
     59             try {         //小于0:abs(count)=阻塞的进程数目
     60                 this.wait();
     61             } catch (InterruptedException e) {
     62                 e.printStackTrace();  
     63             }  
     64         }  
     65     }  
     66     public synchronized void Signal(){   //关键字 synchronized 保证了此操作是一条【原语】
     67         count++;
     68         if(count<=0){//如果有进程阻塞
     69             this.notify();//All
     70         }
     71     }  
     72 }
     73 
     74 class Global{
     75     static syn rmutex=new syn(1);//多个【读者】对readcount进行【互斥】访问
     76     static syn mutex=new syn(1);//多个【写者】对数据区进行【互斥】访问
     77     static int dataZone=0;    //数据区
     78     static int readcount=0;    //用于记录读者的数量
     79     static int data=0;
     80     static int UpBound=20;
     81 }
     82 
     83 class Reader implements Runnable{//读者
     84     int ID=0;
     85     Reader(){}
     86     Reader(int id){ID=id;}
     87     public void run(){
     88         while(Global.data<=Global.UpBound){
     89             //对readcount进行操作
     90             Global.rmutex.Wait();
     91             if(Global.readcount==0){//这是第一个读者,应该阻止写者的进入
     92                 Global.mutex.Wait();
     93             }
     94             Global.readcount++;//读者数量增减
     95             Global.rmutex.Signal();
     96             //对readcount操作结束
     97             
     98             /*
     99              * 进行读操作
    100              */
    101             int readData=Global.dataZone;
    102             System.out.println("读者"+ID+"读出了数据:"+readData);
    103             try {
    104                 Thread.sleep(100);
    105             } catch (InterruptedException e) {
    106                 e.printStackTrace();
    107             }
    108             /*
    109              * 结束读操作
    110              */
    111             
    112             //对readcount进行操作
    113             Global.rmutex.Wait();
    114             Global.readcount--;//读者数量减少
    115             if(Global.readcount==0){//这是最后一个读者,唤醒写者
    116                 Global.mutex.Signal();
    117             }
    118             Global.rmutex.Signal();
    119             //对readcount操作结束
    120         }
    121     }
    122 }
    123 
    124 class Writer implements Runnable{//写者
    125     int ID=0;
    126     Writer(){}
    127     Writer(int id){ID=id;}
    128     public void run(){
    129         while(Global.data<=Global.UpBound){
    130             Global.mutex.Wait();    //申请对数据区进行访问
    131             /*
    132              * 进行写操作
    133              */
    134             Global.data++;
    135             int writeData=Global.data;
    136             System.out.println("写者"+ID+"写入了数据:"+writeData);
    137             Global.dataZone=Global.data;
    138             try {
    139                 Thread.sleep(10);
    140             } catch (InterruptedException e) {
    141                 // TODO Auto-generated catch block
    142                 e.printStackTrace();
    143             }
    144             /*
    145              * 结束写操作
    146              */
    147             Global.mutex.Signal();    //释放数据区,允许其他进程读写
    148         }
    149     }
    150 }
    View Code

    2.公平策略

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

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

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

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

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

      1 package 公平策略;
      2 
      3 import java.util.Scanner;
      4 
      5 
      6 
      7 public class Main {
      8 
      9     public static void main(String[] args) {
     10         System.out.print("请设置读者数目:");
     11         Scanner scan=new Scanner(System.in);
     12         int readNum =scan.nextInt();
     13         
     14         System.out.print("请设置写者数目:");
     15         scan=new Scanner(System.in);
     16         int writeNum =scan.nextInt();        
     17         
     18         System.out.print("请设置循环上限:");
     19         scan=new Scanner(System.in);
     20         Global.UpBound =scan.nextInt();
     21         
     22         scan.close();
     23 
     24         
     25         Reader r[]=new Reader[readNum];
     26         Writer w[]=new Writer[writeNum];
     27         int i;
     28         for(i=0;i<readNum;i++){
     29             r[i]=new Reader(i+1);
     30         }
     31         for(i=0;i<writeNum;i++){
     32             w[i]=new Writer(i+1);
     33         }
     34         Thread []r_t=new Thread[readNum];
     35         Thread []w_t=new Thread[writeNum];
     36         for(i=0;i<readNum;i++){
     37             r_t[i]=new Thread(r[i]);
     38         }        
     39         for(i=0;i<writeNum;i++){
     40             w_t[i]=new Thread(w[i]);
     41         }
     42         for(i=0;i<writeNum;i++){
     43             w_t[i].start();
     44         }    
     45         for(i=0;i<readNum;i++){
     46             r_t[i].start();
     47         }    
     48         
     49 
     50     
     51     }
     52 
     53 }
     54 
     55 class syn{//PV操作类
     56     int count=0;//信号量
     57     syn(){}
     58     syn(int a){count=a;}
     59     public synchronized void Wait(){ //关键字 synchronized 保证了此操作是一条【原语】
     60         count--;
     61         if(count<0){//等于0 :有一个进程进入了临界区
     62             try {         //小于0:abs(count)=阻塞的进程数目
     63                 this.wait();
     64             } catch (InterruptedException e) {
     65                 e.printStackTrace();  
     66             }  
     67         }  
     68     }  
     69     public synchronized void Signal(){   //关键字 synchronized 保证了此操作是一条【原语】
     70         count++;
     71         if(count<=0){//如果有进程阻塞
     72             this.notify();//All
     73         }
     74     }  
     75 }
     76 
     77 class Global{
     78     static syn rmutex=new syn(1);//多个【读者】对readcount进行【互斥】访问
     79     static syn mutex=new syn(1);//多个【写者】对数据区进行【互斥】访问
     80     static int dataZone=0;    //数据区
     81     static int readcount=0;    //用于记录读者的数量
     82     static int data=0;
     83     static int UpBound=20;
     84     static syn wmutex=new syn(1);//表示是否存在【进行】或【等待】的【写者】
     85 }
     86 
     87 class Reader implements Runnable{//读者
     88     int ID=0;
     89     Reader(){}
     90     Reader(int id){ID=id;}
     91     public void run(){
     92         while(Global.data<=Global.UpBound){
     93             Global.wmutex.Wait();//检测是否存在写者,无写者才能进入
     94             
     95             //对readcount进行操作
     96             Global.rmutex.Wait();
     97             if(Global.readcount==0){//这是第一个读者,应该阻止写者的进入
     98                 Global.mutex.Wait();
     99             }
    100             Global.readcount++;//读者数量增减
    101             Global.rmutex.Signal();
    102             //对readcount操作结束
    103             
    104             Global.wmutex.Signal();//恢复wmutex
    105             
    106             /*
    107              * 进行读操作
    108              */
    109             int readData=Global.dataZone;
    110             System.out.println("读者"+ID+"读出了数据:"+readData);
    111             try {
    112                 Thread.sleep(100);
    113             } catch (InterruptedException e) {
    114                 e.printStackTrace();
    115             }
    116             /*
    117              * 结束读操作
    118              */
    119             
    120             //对readcount进行操作
    121             Global.rmutex.Wait();
    122             Global.readcount--;//读者数量减少
    123             if(Global.readcount==0){//这是最后一个读者,唤醒写者
    124                 Global.mutex.Signal();
    125             }
    126             Global.rmutex.Signal();
    127             //对readcount操作结束
    128             
    129             
    130         }
    131     }
    132 }
    133 
    134 class Writer implements Runnable{//写者
    135     int ID=0;
    136     Writer(){}
    137     Writer(int id){ID=id;}
    138     public void run(){
    139         while(Global.data<=Global.UpBound){
    140             Global.wmutex.Wait();
    141             Global.mutex.Wait();    //申请对数据区进行访问
    142             /*
    143              * 进行写操作
    144              */
    145             Global.data++;
    146             int writeData=Global.data;
    147             System.out.println("写者"+ID+"写入了数据:"+writeData);
    148             Global.dataZone=Global.data;
    149             try {
    150                 Thread.sleep(10);
    151             } catch (InterruptedException e) {
    152                 // TODO Auto-generated catch block
    153                 e.printStackTrace();
    154             }
    155             /*
    156              * 结束写操作
    157              */
    158             Global.mutex.Signal();    //释放数据区,允许其他进程读写
    159             Global.wmutex.Signal();
    160         }
    161     }
    162 }
    View Code

    3.写者优先

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

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

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

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

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

      1 package 写者优先;
      2 
      3 import java.util.Scanner;
      4 
      5 
      6 
      7 public class Main {
      8 
      9     public static void main(String[] args) {
     10         System.out.print("请设置读者数目:");
     11         Scanner scan=new Scanner(System.in);
     12         int readNum =scan.nextInt();
     13         
     14         System.out.print("请设置写者数目:");
     15         scan=new Scanner(System.in);
     16         int writeNum =scan.nextInt();        
     17         
     18         System.out.print("请设置循环上限:");
     19         scan=new Scanner(System.in);
     20         Global.UpBound =scan.nextInt();
     21         
     22         scan.close();
     23 
     24         
     25         Reader r[]=new Reader[readNum];
     26         Writer w[]=new Writer[writeNum];
     27         int i;
     28         for(i=0;i<readNum;i++){
     29             r[i]=new Reader(i+1);
     30         }
     31         for(i=0;i<writeNum;i++){
     32             w[i]=new Writer(i+1);
     33         }
     34         Thread []r_t=new Thread[readNum];
     35         Thread []w_t=new Thread[writeNum];
     36         for(i=0;i<readNum;i++){
     37             r_t[i]=new Thread(r[i]);
     38         }        
     39         for(i=0;i<writeNum;i++){
     40             w_t[i]=new Thread(w[i]);
     41         }
     42         for(i=0;i<writeNum;i++){
     43             w_t[i].start();
     44         }    
     45         for(i=0;i<readNum;i++){
     46             r_t[i].start();
     47         }    
     48         
     49 
     50     
     51     }
     52 
     53 }
     54 
     55 class syn{//PV操作类
     56     int count=0;//信号量
     57     syn(){}
     58     syn(int a){count=a;}
     59     public synchronized void Wait(){ //关键字 synchronized 保证了此操作是一条【原语】
     60         count--;
     61         if(count<0){//等于0 :有一个进程进入了临界区
     62             try {         //小于0:abs(count)=阻塞的进程数目
     63                 this.wait();
     64             } catch (InterruptedException e) {
     65                 e.printStackTrace();  
     66             }  
     67         }  
     68     }  
     69     public synchronized void Signal(){   //关键字 synchronized 保证了此操作是一条【原语】
     70         count++;
     71         if(count<=0){//如果有进程阻塞
     72             this.notify();//All
     73         }
     74     }  
     75 }
     76 
     77 class Global{
     78     static syn mutex=new syn(1);//控制互斥访问的数据区    
     79     static syn rmutex=new syn(1);//多个【读者】对readcount进行【互斥】访问
     80     static syn wmutex=new syn(1);//多个【写者】对writecount进行【互斥】访问
     81     static syn readable=new syn(1);//表示当前是否有写者
     82     
     83     static int dataZone=0;    //数据区
     84     static int readcount=0;    //用于记录读者的数量
     85     static int writecount=0;    //用于记录读者的数量
     86     
     87     static int data=0;
     88     static int UpBound=20;
     89 
     90 }
     91 
     92 class Reader implements Runnable{//读者
     93     int ID=0;
     94     Reader(){}
     95     Reader(int id){ID=id;}
     96     public void run(){
     97         while(Global.data<=Global.UpBound){
     98             Global.readable.Wait();//检测是否存在写者,无写者才能进入
     99             
    100             //对readcount进行操作
    101             Global.rmutex.Wait();
    102             if(Global.readcount==0){//这是第一个读者,应该阻止写者的进入
    103                 Global.mutex.Wait();
    104             }
    105             Global.readcount++;//读者数量增减
    106             Global.rmutex.Signal();
    107             //对readcount操作结束
    108             
    109             Global.readable.Signal();//恢复readable
    110             
    111             /*
    112              * 进行读操作
    113              */
    114             int readData=Global.dataZone;
    115             System.out.println("读者"+ID+"读出了数据:"+readData);
    116             try {
    117                 Thread.sleep(100);
    118             } catch (InterruptedException e) {
    119                 e.printStackTrace();
    120             }
    121             /*
    122              * 结束读操作
    123              */
    124             
    125             //对readcount进行操作
    126             Global.rmutex.Wait();
    127             Global.readcount--;//读者数量减少
    128             if(Global.readcount==0){//这是最后一个读者,唤醒写者
    129                 Global.mutex.Signal();
    130             }
    131             Global.rmutex.Signal();
    132             //对readcount操作结束
    133         }
    134     }
    135 }
    136 
    137 class Writer implements Runnable{//写者
    138     int ID=0;
    139     Writer(){}
    140     Writer(int id){ID=id;}
    141     public void run(){
    142         while(Global.data<=Global.UpBound){
    143             Global.wmutex.Wait();//准备修改writecount
    144             if(Global.writecount==0) Global.readable.Wait();//如果是第一个读者,则阻止后续读者进入
    145             Global.writecount++;
    146             Global.wmutex.Signal();//结束对writecount的修改
    147             
    148             Global.mutex.Wait();    //申请对数据区进行访问
    149             /*
    150              * 进行写操作
    151              */
    152             Global.data++;
    153             int writeData=Global.data;
    154             System.out.println("写者"+ID+"写入了数据:"+writeData);
    155             Global.dataZone=Global.data;
    156             try {
    157                 Thread.sleep(10);
    158             } catch (InterruptedException e) {
    159                 // TODO Auto-generated catch block
    160                 e.printStackTrace();
    161             }
    162             /*
    163              * 结束写操作
    164              */
    165             Global.mutex.Signal();    //释放数据区,允许其他进程读写
    166 
    167             Global.wmutex.Wait();//准备修改writecount
    168             Global.writecount--;            
    169             if(Global.writecount==0) Global.readable.Signal();//如果是最后一个写者,唤醒读者
    170             Global.wmutex.Signal();//结束对writecount的修改
    171         }
    172     }
    173 }
    View Code

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

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

  • 相关阅读:
    Linux统计文件个数
    python string与list互转
    Python中请使用isinstance()判断变量类型
    xpath提取多个标签下的text
    内存盘
    Watchdog
    渗透测试
    GMT与UTC简介
    ASN.1(抽象语法标记)
    Linux nmap
  • 原文地址:https://www.cnblogs.com/TQCAI/p/7704872.html
Copyright © 2011-2022 走看看