上一節中,通過while和notifyAll解決了多個生產者,消費者對共享資源的訪問問題,現在開始升級
但是,仍然有改進之處,主要體現在兩點:
1)使用新版本1.5開始后的鎖Lock解決,目的將其全部替換實現相同功能
2)由於notifyAll喚醒的是己方和對方線程,我們優化的是只喚醒對方進程
方案1,使用while和notifyAll,synchronized解決多線程訪問
代碼:

/* ProducterConsumerDemo解決了只有兩個線程共享資源的生產消費問題,主要利用標志位的互斥解決 本程序致力於解決多出現多個生產者,多個消費者的時候,依然能夠達到生產一次,消費一次的功能 : 解決的方法就是:1)在被喚醒之后仍然進行條件判斷,去檢查要改的數字是否滿足條件,如果不滿足條件就繼續睡眠。把兩個方法中的if改為while即可。 當然,此時仍會出現問題,就是所以線程都等待,失去資格 2)需要將notify()改成notifyAll() */ class ProducterConsumerDemo2 { public static void main(String[] args) { Resources r =new Resources(); Productor pro =new Productor(r); Consumer con = new Consumer(r); Thread t1 =new Thread(pro); Thread t2 =new Thread(pro);//多個生產者 Thread t3 =new Thread(con); Thread t4 =new Thread(con);//多個消費者 t1.start(); t2.start(); t3.start(); t4.start(); System.out.println("Hello World!"); } } class Resources { private String name; private int count =1; private boolean flag =false; public synchronized void set(String name) { //1)循環判斷 while(flag) try{this.wait();}catch(Exception e){} this.name = name+"--"+count++; System.out.println(Thread.currentThread().getName()+"生產者"+this.name); flag =true; //2)喚醒所有進程 this.notifyAll(); } public synchronized void out() { //1)循環判斷 while(!flag) try{this.wait();}catch(Exception e){} System.out.println(Thread.currentThread().getName()+" ....消費者...."+this.name); flag =false; //2)喚醒所有進程 this.notifyAll(); } } class Productor implements Runnable { private Resources res; Productor(Resources res){ this.res =res; } public void run(){ while(true){ res.set("++商品++"); } } } class Consumer implements Runnable { private Resources res; Consumer(Resources res){ this.res =res; } public void run(){ while(true){ res.out(); } } }
方案2,解決改進1)的問題
升級版:
使用Lock來替換synchronized,wait,notify,nonifyAll語法和語句的使用
不需要同步,不需要notify
記得需要導包:
java.util.concurrent.locks
主要改動:
自定義鎖 ---》 Condition對象 --》signallAll
condition.await() === try{this.wait();}catch(Exception e){}
synchronized刪除,異常拋出,使用finally解鎖
1 /* 2 3 本程序致力於解決多出現多個生產者,多個消費者的時候,依然能夠達到生產一次,消費一次的功能 4 : 5 解決的方法就是:1)在被喚醒之后仍然進行條件判斷,去檢查要改的數字是否滿足條件,如果不滿足條件就繼續睡眠。把兩個方法中的if改為while即可。 6 當然,此時仍會出現問題,就是所以線程都等待,失去資格 7 2)需要將notify()改成notifyAll() 8 9 升級版: 10 使用Lock來替換synchronized,wait,notify,nonifyAll語法和語句的使用 11 不需要同步,不需要notify 12 */ 13 import java.util.concurrent.locks.*; 14 class ProducterConsumerDemo3 15 { 16 public static void main(String[] args) 17 { 18 Resources r =new Resources(); 19 Productor pro =new Productor(r); 20 Consumer con = new Consumer(r); 21 22 Thread t1 =new Thread(pro); 23 Thread t2 =new Thread(pro);//多個生產者 24 Thread t3 =new Thread(con); 25 Thread t4 =new Thread(con);//多個消費者 26 t1.start(); 27 t2.start(); 28 t3.start(); 29 t4.start(); 30 System.out.println("Hello World!"); 31 } 32 } 33 34 class Resources 35 { 36 private String name; 37 private int count =1; 38 private boolean flag =false; 39 private Lock lock = new ReentrantLock(); 40 41 private Condition condition = lock.newCondition(); 42 43 public void set(String name) throws InterruptedException 44 { 45 lock.lock(); 46 try 47 { 48 //1)循環判斷 49 while(flag) 50 //如果為真,放棄資格 51 condition.await(); //會拋出異常 52 this.name = name+"--"+count++; 53 54 System.out.println(Thread.currentThread().getName()+"生產者"+this.name); 55 flag =true; 56 //2)使用condition喚醒所有進程 57 condition.signalAll(); //如果使用condition.signal()會出現相互等待狀況,都失去資格 58 } 59 finally 60 { 61 lock.unlock(); 62 } 63 64 65 } 66 public void out() throws InterruptedException 67 { 68 lock.lock(); 69 try 70 { 71 //1)循環判斷 72 while(!flag) 73 condition.await(); 74 75 System.out.println(Thread.currentThread().getName()+" ....消費者...."+this.name); 76 flag =false; 77 //2)使用condition喚醒所有進程 78 condition.signalAll(); 79 } 80 finally //防止當前線程拿到鎖后拋異常一直不釋放鎖 81 { 82 lock.unlock(); 83 } 84 85 86 } 87 } 88 89 class Productor implements Runnable 90 { 91 private Resources res; 92 Productor(Resources res){ 93 this.res =res; 94 } 95 public void run(){ 96 while(true){ 97 try 98 { 99 res.set("++商品++"); //需要拋出異常 100 } 101 catch (InterruptedException e) 102 { 103 } 104 105 } 106 } 107 108 } 109 110 class Consumer implements Runnable 111 { 112 private Resources res; 113 Consumer(Resources res){ 114 this.res =res; 115 } 116 public void run(){ 117 while(true){ 118 try 119 { 120 res.out(); //需要拋出異常 121 } 122 catch (InterruptedException e) 123 { 124 } 125 126 } 127 } 128 129 }
此時實現功能和方案1功能一樣
方案3,在方案2的基礎上解決改進2)的問題
加強升級版:
此版本為最終版,主要在使用鎖lock的基礎上,加上喚醒對方(不包括己方)進程的優化
1 /* 2 3 本程序致力於解決多出現多個生產者,多個消費者的時候,依然能夠達到生產一次,消費一次的功能 4 : 5 解決的方法就是:1)在被喚醒之后仍然進行條件判斷,去檢查要改的數字是否滿足條件,如果不滿足條件就繼續睡眠。把兩個方法中的if改為while即可。 6 當然,此時仍會出現問題,就是所以線程都等待,失去資格 7 2)需要將notify()改成notifyAll() 8 9 升級版: 10 使用Lock來替換synchronized,wait,notify,nonifyAll語法和語句的使用 11 不需要同步,不需要notify 12 ------------ 13 加強升級版: 14 此版本為最終版,主要在使用鎖lock的基礎上,加上喚醒對方(不包括己方)進程的優化 15 通過一個鎖建立多個condition對象來解決 16 17 流程: 18 生產者拿到鎖,執行,判斷沒有真,繼續執行,生產完畢后喚醒消費者來消費 生產者喚醒消費者 19 消費者拿到鎖,執行,判斷沒有假,繼續執行,消費完畢后喚醒生產者繼續生產 消費者喚醒生產者 20 21 */ 22 import java.util.concurrent.locks.*; 23 class ProducterConsumerDemo4 24 { 25 public static void main(String[] args) 26 { 27 Resources r =new Resources(); 28 Productor pro =new Productor(r); 29 Consumer con = new Consumer(r); 30 31 Thread t1 =new Thread(pro); 32 Thread t2 =new Thread(pro);//多個生產者 33 Thread t3 =new Thread(con); 34 Thread t4 =new Thread(con);//多個消費者 35 t1.start(); 36 t2.start(); 37 t3.start(); 38 t4.start(); 39 System.out.println("Hello World!"); 40 } 41 } 42 43 class Resources 44 { 45 private String name; 46 private int count = 1; 47 private boolean flag =false; 48 private Lock lock = new ReentrantLock(); 49 50 private Condition condition_pro = lock.newCondition(); //使用lock建立生產者的condition對象 51 private Condition condition_con = lock.newCondition(); //使用lock建立消費者的condition對象 52 53 public void set(String name) throws InterruptedException 54 { 55 lock.lock(); 56 try 57 { 58 //1)循環判斷 59 while(flag) 60 //如果為真,放棄生產者的資格 61 condition_pro.await(); //會拋出異常 62 this.name = name+"--"+count++; 63 64 System.out.println(Thread.currentThread().getName()+"生產者"+this.name); 65 flag =true; 66 //2)使用消費condition喚醒進程 67 condition_con.signal(); //生產者生產完畢后,喚醒消費者的進程(不再是signalAll) 68 } 69 finally 70 { 71 lock.unlock(); 72 } 73 74 75 } 76 public void out() throws InterruptedException 77 { 78 lock.lock(); 79 try 80 { 81 //1)循環判斷 82 while(!flag) 83 //如果為假,放棄消費者的資格 84 condition_con.await(); 85 86 System.out.println(Thread.currentThread().getName()+" ....消費者...."+this.name); 87 flag =false; 88 //2)使用生產者condition喚醒進程 89 condition_pro.signal(); //消費者消費完畢后,喚醒生產者的進程 90 } 91 finally //防止當前線程拿到鎖后拋異常一直不釋放鎖 92 { 93 lock.unlock(); 94 } 95 96 97 } 98 } 99 100 class Productor implements Runnable 101 { 102 private Resources res; 103 Productor(Resources res){ 104 this.res =res; 105 } 106 public void run(){ 107 while(true){ 108 try 109 { 110 res.set("++商品++"); //需要拋出異常 111 } 112 catch (InterruptedException e) 113 { 114 } 115 116 } 117 } 118 119 } 120 121 class Consumer implements Runnable 122 { 123 private Resources res; 124 Consumer(Resources res){ 125 this.res =res; 126 } 127 public void run(){ 128 while(true){ 129 try 130 { 131 res.out(); //需要拋出異常 132 } 133 catch (InterruptedException e) 134 { 135 } 136 137 } 138 } 139 140 }
圖示: