注 :本文應結合【天勤筆記】進行學習。
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 }
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 }
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 }
4.三種情況下運行結果的對比
在同一組測試數據下,三種情況的運行結果見上圖。左為讀者優先,中為公平策略,右為寫者優先。可見左圖讀者進行了大量的插隊操作,中圖的讀者與寫者都是交替進行的,右圖的寫者從一開始就在插隊。