java線程之多個生產者消費者2.0


上一節中,通過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();
        }
    }

}
ProducterConsumerDemo2.java

方案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 }

圖示:


免責聲明!

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



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