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 }

图示:

时间: 2024-10-24 21:23:44

java线程之多个生产者消费者2.0的相关文章

Java线程:并发协作-生产者消费者模型

对于多线程程序来说,不管任何编程语言,生产者消费者模型都是最经典的. 实际上,准确的说应该是"生产者-消费者-仓储"模型,离开了仓储,生产者消费者模型就显得没有说服力了. 对于此模型,应该明确以下几点: 生产者仅仅在仓储未满时候生产,仓满则停止生产. 消费者仅仅在仓储有产品时候才能消费,仓空则等待. 当消费者发现仓储没有产品的时候会通知生产者生产. 生产者在生产出可消费产品时候,应该通知消费者去消费. 此模型将要结合java.lang.Object的wait与notify,notify

Ruby:线程实现经典的生产者消费者问题

运行结果: ProAndCon 0 produced 1 produced consumed 0 2 produced 3 produced consumed 1 consumed 2 consumed 3 4 produced consumed 4 5 produced consumed 5 转载自:http://www.oschina.net/code/snippet_1045481_33311 Ruby:线程实现经典的生产者消费者问题,布布扣,bubuko.com

Linux平台下线程同步,实现“生产者消费者问题”

(1)线程同步,实现"生产者消费者问题" 要求:缓冲区大小为20,生产者每次放一个产品,消费者每次取走一个产品:生产者和消费者至少2个. (2)代码如下: #include <stdio.h> #include <pthread.h> #include <unistd.h> #include <sched.h> void *producter_f (void *arg); /*生产者*/ void *consumer_f (void *a

java基础——线程通信机制,生产者消费者

package communication; /* 使用两个线程1,2交替打印1-100 线程通信方法: 1.wait():一旦执行此方法,当前线程进入阻塞态,并释放锁 2.notify():会唤醒被wait的一个线程,如果有多个线程wait,则唤醒优先级高的 3.notifyAll():唤醒所有被wait的线程 说明: 1.wait(),notify(),notifyAll()使用在同步代码块或同步方法中,不能用在lock方法中 2.这三个方法的调用者必须是同步代码块或同步方法中的锁对象(同步

Java多线程之并发协作生产者消费者设计模式

两个线程一个生产者个一个消费者 需求情景 两个线程,一个负责生产,一个负责消费,生产者生产一个,消费者消费一个 涉及问题 同步问题:如何保证同一资源被多个线程并发访问时的完整性.常用的同步方法是采用标记或加锁机制 wait() / nofity() 方法是基类Object的两个方法,也就意味着所有Java类都会拥有这两个方法,这样,我们就可以为任何对象实现同步机制. wait()方法:当缓冲区已满/空时,生产者/消费者线程停止自己的执行,放弃锁,使自己处于等等状态,让其他线程执行. notify

Java 多线程学习笔记:生产者消费者问题

前言:最近在学习Java多线程,看到ImportNew网上有网友翻译的一篇文章<阻塞队列实现生产者消费者模式>.在文中,使用的是Java的concurrent包中的阻塞队列来实现.在看完后,自行实现阻塞队列. (一)准备 在多线程中,生产者-消费者问题是一个经典的多线程同步问题.简单来说就是有两种线程(在这里也可以做进程理解)——生产者和消费者,他们共享一个固定大小的缓存区(如一个队列).生产者负责产生放入新数据,消费者负责取出缓存区的数据.具体介绍请参考 Producer-consumer

java 多线程并发系列之 生产者消费者模式的两种实现

在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题.该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度. 为什么要使用生产者和消费者模式 在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程.在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据.同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者.为了解决这种生产消费能力不均衡的问题,所以便有了生产者和消费者模式. 什么是生

黑马程序员——java——线程间的通讯 生产者与消费者

线程间的的通讯  生产者与消费者 public class TestDemos3 { public static void main(String[] args) { Res r = new Res(); Input in = new Input(r); Output out = new Output(r); Thread t1 = new Thread(in); Thread t2 = new Thread(out); t1.start(); t2.start(); } } class Res

java线程详解

Java线程:概念与原理 一.操作系统中线程和进程的概念 现在的操作系统是多任务操作系统.多线程是实现多任务的一种方式. 进程是指一个内存中运行的应用程序,每个进程都有自己独立的一块内存空间,一个进程中可以启动多个线程.比如在Windows系统中,一个运行的exe就是一个进程. 线程是指进程中的一个执行流程,一个进程中可以运行多个线程.比如java.exe进程中可以运行很多线程.线程总是属于某个进程,进程中的多个线程共享进程的内存. “同时”执行是人的感觉,在线程之间实际上轮换执行. 二.Jav