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 }

图示:

posted @ 2015-12-18 17:46  平常心,平常心  阅读(4064)  评论(0编辑  收藏  举报