文档章节

生产者与消费者

Mr_菜
 Mr_菜
发布于 2016/04/08 17:15
字数 1007
阅读 7
收藏 0

wait():  等待   如果线程执行了wait方法,那么该线程会进入等待的状态,等待状态下的线程必须要被其他线程调用notify方法才能唤醒。
notify(): 唤醒    唤醒线程池等待线程其中的一个。
notifyAll() : 唤醒线程池所有等待 线程。


wait与notify方法要注意的事项:
    1. wait方法与notify方法是属于Object对象 的。
    2. wait方法与notify方法必须要在同步代码块或者是同步函数中才能 使用。
    3. wait方法与notify方法必需要由锁对象调用。


下面我们来看看经典的生产者与消费者问题:

class Product{
    String name;
    double price;
}
//生产者
class Producer extends Thread{
    
    Product p;
    public Producer(Product p){
        this.p = p;
    }
    @Override
    public void run() {
            int i =0;
            while(true){
                if (i%2==0) {
                    p.name="苹果";
                    try {
                        Thread.sleep(1);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    p.price=12.5;        
                }else {
                    p.name="西瓜";
                    p.price=7.5;
                }
                System.out.println("生产者产出了"+p.name + "价格"+p.price);
                i++;
            }
        }
    }

 
//消费者
 class Customer extends Thread{
     
     Product p;
    
     public  Customer(Product p) {
            this.p = p;
        }
     @Override
    public void run() {
         while(true){
            System.out.println("消费者消费了"+p.name+" 价格:"+ p.price);
        }
    }
 }
public class Demo5 {

    public static void main(String[] args) {  
        Product p = new Product();
        Producer producer = new Producer(p);
        Customer customer = new Customer(p);
        producer.start();
        customer.start();
    }

}

首先,我们创建了一个产品类,还有生产者和消费者两个线程。为了保证这两个线程共享同一个产品对象,我在两个线程中分别创建了一个构造方法,将对象p传入。

运行截图如下:

第一次运行可以看到出现了价格混乱的线程安全问题,苹果的价格应该是12.5,在运行中变成了7.5;


解决这个问题,只需要给两个线程加上一把锁就可以了

改动如下:

class Producer extends Thread{
    
    Product p;
    public Producer(Product p){
        this.p = p;
    }
    @Override
    public void run() {
            int i =0;
            while(true){
                synchronized (p) {
                        if (i%2==0) {
                        p.name="苹果";
                        try {
                            Thread.sleep(1);
                        } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                        p.price=12.5;        
                    }else {
                        p.name="西瓜";
                        p.price=7.5;
                    }
                    System.out.println("生产者产出了"+p.name + "价格"+p.price);
                    i++;
                }
            }
        }
    }

 
//消费者
 class Customer extends Thread{
     
     Product p;
    
     public  Customer(Product p) {
            this.p = p;
        }
     @Override
    public void run() {
         while(true){
             synchronized (p) {
                 System.out.println("消费者消费了"+p.name+" 价格:"+ p.price);
            }
        }
    }
 }


其次,在控制台中消费与生产十分混乱


我们有了下面的需求:


我们需要引入下面两个方法

wait():  等待   如果线程执行了wait方法,那么该线程会进入等待的状态,等待状态下的线程必须要被其他线程调用notify方法 才能唤醒。
notify(): 唤醒    唤醒线程池等待线程其中的一个。


wait与notify方法要注意的事项:
    1. wait方法与notify方法是属于Object对象 的。
    2. wait方法与notify方法必须要在同步代码块或者是同步函数中才能 使用。
    3. wait方法与notify方法必需要由锁对象调用。


为了实现上述需求,我们必须要判断这个产品是否存在,可以在代码中设置一个flag;

class Product{
    
    String name;  //名字
    
    double price;  //价格
    
    boolean flag = false; //产品是否生产完毕的标识,默认情况是没有生产完成。
    
}

生产者线程改动如下:

public void run() {
        int i = 0 ; 
        while(true){
         synchronized (p) {
            if(p.flag==false){
                 if(i%2==0){
                     p.name = "苹果";
                     p.price = 12.5;
                 }else{
                     p.name="西瓜";
                     p.price = 7.5;
                 }
                 System.out.println("生产者生产出了:"+ p.name+" 价格是:"+ p.price);
                 p.flag = true;
                 i++;
                 p.notifyAll(); //唤醒消费者去消费
            }else{
                //已经生产 完毕,等待消费者先去消费
                try {
                    p.wait();   //生产者等待
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }       
        }    
      }    
    }
}

消费者线程改动如下:

    public void run() {
        while(true){
            synchronized (p) {    
                if(p.flag==true){  //产品已经生产完毕
                    System.out.println("消费者消费了"+p.name+" 价格:"+ p.price);
                    p.flag = false; 
                    p.notifyAll(); // 唤醒生产者去生产
                }else{
                    //产品还没有生产,应该 等待生产者先生产。
                    try {
                        p.wait(); //消费者也等待了...
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }    
    }
}

最后运行结果片段如下:



© 著作权归作者所有

Mr_菜
粉丝 1
博文 13
码字总数 8804
作品 0
西安
程序员
私信 提问
加载中

评论(1)

Jader-D
Jader-D
好久没来看啦,坚持呐
java:一个生产者消费者模式的简单实现

先啰嗦一点: 由于最近工作中,涉及到生产者消费者设计模式,对此有一些体会,所以总结一下,与大家分享。 1、什么是生产者消费者模式 在工作中,大家可能会碰到这样一种情况:某个模块负责产...

jackson_open
2014/04/03
1K
0
java:一个生产者消费者模式的简单实现

先啰嗦一点: 由于最近工作中,涉及到生产者消费者设计模式,对此有一些体会,所以总结一下,与大家分享。 1、什么是生产者消费者模式 在 工作中,大家可能会碰到这样一种情况:某个模块负责...

jackson_open
2014/02/14
91
0
生产者/消费者模式

在实际的软件开发过程中,经常会碰到如下场景:某个模块负责产生数据,这些数据由另一个模块来负责处理(此处的模块是广义的,可以是类、函数、线程、进程等)。产生数据的模块,就形象地称为...

pan_1308
2016/10/27
324
0
【python队列】生产者消费者模型

生产者消费者模型: 在软件开发的过程中,经常碰到这样的场景: 某些模块负责生产数据,这些数据由其他模块来负责处理(此处的模块可能是:函数、线程、进程等)。产生数据的模块称为生产者,...

等你的破船
2018/05/18
0
0
springboot+rabbitmq整合

1.安装好rabbitmq 2.新建一个springBoot项目:rabbitmq_demo 3.添加pom依赖: 4.application.properties: 5.启动类声明一个Queue,用于测试: 多场景实现: 1.单生产者和单消费者 生产者1: ...

狼王黄师傅
2018/10/19
75
0

没有更多内容

加载失败,请刷新页面

加载更多

cpu load过高问题排查

load average的概念 top命令中load average显示的是最近1分钟、5分钟和15分钟的系统平均负载。 系统平均负载被定义为在特定时间间隔内运行队列中(在CPU上运行或者等待运行多少进程)的平均进程...

mskk
17分钟前
3
0
用spring boot 实现websocket

import java.io.IOException;import javax.websocket.OnClose;import javax.websocket.OnError;import javax.websocket.OnMessage;import javax.websocket.OnOpen;import java......

jingshishengxu
27分钟前
2
0
shell介绍,命令历史,命令补全和别名,通配符,输入输出重定向,管道符和作业控制

shell介绍 可以使用 yum list |grep zsh 或者 yum list |grep ksh 这样可以搜索 zsh 和 ksh ,有需要的话可以安装 总之,默认使用的就是 .bash shell 命令历史 输入过的命令会被保存在一个文...

doomcat
44分钟前
7
0
1995年的资深工程师,和你谈谈如何进阶

1995年的资深工程师,和你谈谈如何进阶 自我介绍 网络ID:杭城小刘,城市:顾名思义,人在杭州。1995年出生,本科毕业,现在是一名 iOS 资深工程师,年薪 35w。兴趣爱好广泛:乒乓球、美食、...

杭城小刘
今天
10
0
Kafka 面试题

1.Kafka中的ISR、AR代表什么? ISR:与leader保持同步的follower集合 AR:分区的所有副本 2.Kafka中的HW、LEO分别代表什么? LEO:每个副本的最后条消息的offset HW:一个分区中所有副本最小...

GrayWorld
今天
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部