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.三種情況下運行結果的對比

 

在同一組測試數據下,三種情況的運行結果見上圖。左為讀者優先,中為公平策略,右為寫者優先。可見左圖讀者進行了大量的插隊操作,中圖的讀者與寫者都是交替進行的,右圖的寫者從一開始就在插隊。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM