温故一下上一节所学习的生产者消费者代码:

两个线程时:

通过标志位flag的if判断和同步函数互斥较好解决两个线程,一个生产者、一个消费者交替执行的功能

类名:ProducterConsumerDemo.java

代码:

 class  ProducterConsumerDemo
{
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(con);
t1.start();
t2.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)
{
if(flag)
try{this.wait();}catch(Exception e){}
this.name = name+"--"+count++; System.out.println(Thread.currentThread().getName()+"生产者"+this.name);
flag =true;
//唤醒对方进程
this.notify(); }
public synchronized void out()
{
if(!flag)
try{this.wait();}catch(Exception e){} System.out.println(Thread.currentThread().getName()+" ....消费者...."+this.name);
flag =false;
//唤醒对方进程
this.notify(); }
} 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();
}
} }

ProducterConsumerDemo.java

如果再多加上两个线程呢?

  即把其中的ProducterConsumerDemo类改为如下:

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!");
}
}

运行后发现,加上t3和t4之后结果就错了。

  为什么两个线程的时候执行结果正确而四个线程的时候就不对了呢?

  因为线程在wait()的时候,接收到其他线程的通知,即往下执行,不再进行判断。两个线程的情况下,唤醒的肯定是另一个线程;但是在多个线程的情况下,执行结果就会混乱无序。

  比如,一个可能的情况是,一个增加线程执行的时候,其他三个线程都在wait,这时候第一个线程调用了notify()方法,其他线程都将被唤醒,然后执行各自的增加或减少方法。

  解决的方法就是:在被唤醒之后仍然进行条件判断,去检查要改的数字是否满足条件,如果不满足条件就继续睡眠。

                           1)把两个方法中的if改为while即可。

           2)需要将notify()改成notifyAll()

代码:

 /*
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();
}
} }

效果:

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

  1. java线程之多个生产者消费者2.0

    上一节中,通过while和notifyAll解决了多个生产者,消费者对共享资源的访问问题,现在开始升级 但是,仍然有改进之处,主要体现在两点: 1)使用新版本1.5开始后的锁Lock解决,目的将其全部 ...

  2. Java阻塞队列(BlockingQueue)实现 生产者/消费者 示例

    Java阻塞队列(BlockingQueue)实现 生产者/消费者 示例 本文由 TonySpark 翻译自 Javarevisited.转载请参见文章末尾的要求. Java.util.concurr ...

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

    两个线程一个生产者个一个消费者 需求情景 两个线程,一个负责生产,一个负责消费,生产者生产一个,消费者消费一个 涉及问题 同步问题:如何保证同一资源被多个线程并发访问时的完整性.常用的同步方法是采用标 ...

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

    前言:最近在学习Java多线程,看到ImportNew网上有网友翻译的一篇文章<阻塞队列实现生产者消费者模式>.在文中,使用的是Java的concurrent包中的阻塞队列来实现.在看完后 ...

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

    在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题.该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度. 为什么要使用生产者和消费者模式 在线程世界里,生产者就是生产数据 ...

  6. java多线程系列15 设计模式 生产者 - 消费者模式

    生产者-消费者 生产者消费者模式是一个非常经典的多线程模式,比如我们用到的Mq就是其中一种具体实现 在该模式中 通常会有2类线程,消费者线程和生产者线程 生产者提交用户请求 消费者负责处理生产者提交的 ...

  7. python进阶:Python进程、线程、队列、生产者/消费者模式、协程

    一.进程和线程的基本理解 1.进程 程序是由指令和数据组成的,编译为二进制格式后在硬盘存储,程序启动的过程是将二进制数据加载进内存,这个启动了的程序就称作进程(可简单理解为进行中的程序).例如打开一个 ...

  8. 【Java并发编程】:生产者—消费者模型

    生产者消费者问题是线程模型中的经典问题:生产者和消费者在同一时间段内共用同一存储空间,生产者向空间里生产数据,而消费者取走数据. 这里实现如下情况的生产--消费模型: 生产者不断交替地生产两组数据“姓 ...

  9. java信号量PV操作 解决生产者-消费者问题

    package test1; /** * 该例子演示生产者和消费者的问题(设只有一个缓存空间.一个消费者和一个生产者) * MySystem类定义了缓冲区个数以及信号量 * @author HYY * ...

随机推荐

  1. LPC1768的USB使用-枚举过程

    枚举过程如下 #ifndef __USBCORE_H__ #define __USBCORE_H__ /* USB端点0 发送数据结构体*/ typedef struct _USB_EP_DATA { ...

  2. DDR工作原理(转)

    源:DDR工作原理 DDR SDRAM全称为Double Data Rate SDRAM,中文名为“双倍数据流SDRAM”.DDR SDRAM在原有的SDRAM的基础上改进而来.也正因为如此,DDR能 ...

  3. POJ 2609 Ferry Loading

    双塔DP+输出路径. 由于内存限制,DP只能开滚动数组来记录. 我的写法比较渣,但是POJ能AC,但是ZOJ依旧MLE,更加奇怪的是Uva上无论怎么改都是WA,其他人POJ过的交到Uva也是WA. # ...

  4. NSDate常用代码范例

    NSDate常用代码范例 NSDate类用于保存时间值,同时提供了一些方法来处理一些基于秒级别时差(Time Interval)运算和日期之间的早晚比较等. 1. 创建或初始化可用以下方法 用于创建N ...

  5. objective-c之各种数值

    各种数值 NSArray和NSDictionary都只能存储对象,不能存储任何基本类型的数据,如int,float,struct.因此我们可以用对象来封装基本的数值. NSNumber Cocoa提供 ...

  6. MPU6050首例整合性6轴的姿态模块(转)

    源:MPU6050首例整合性6轴的姿态模块 Mpu6050为全球首例整合3轴陀螺仪.3轴加速器.含9轴融合演:MPU-6000为全球首例整合性6轴运动处理组件,相较于多组件方案,免除了组合陀螺仪与加速 ...

  7. Java 汉子转拼音

    1. 引入: pinyin4j-1.1.0 包;  http://pan.baidu.com/s/1eQ8a874 2. 转换; private static String ChineseToPiny ...

  8. [Angular Tutorial] 12 -Event Handlers

    在这一步中,您将会在电话细节页面添加一个可点击的电话图片转换器. ·电话细节页面展示了当前电话的一张大图片和几张相对较小的略图.如果我们能仅仅通过点击略图就能把大图片换成略图就好了.让我们看看用Ang ...

  9. linx建立用戶&組

    groupadd  test                  创建test用户组 useradd  user1                  创建user1用户 passwd   user1   ...

  10. 使用YUIDoc生成JS文档

    其实YUIDoc主页已经写的比较清晰了,但有一些概念和细节再点出一些注意的地方. 目前最新的YUIDoc使用nodejs进行开发安装和使用都非常的方便. 我们只需要将我们的代码加上必要的注释,便可以很 ...