生产者-消费者模型(阿里云开发者社区学习笔记)

生产者与消费者的操作

在多线程的开发过程之中最为著名的案例就是生产者与消费者操作,该操作的主要流程如下:
‒ 生产者负责信息内容的生产
‒ 每当生产者生产完成一项完整的信息之后消费者要从这里取走信息
‒ 如果生产者没有生产完则消费者要等待它完成,如果消费者还没有对信息进行消费,则生产者应该等待消费处理完成后再继续生产

可以将生产者与消费者定义为两个独立的线程类对象,但是对于现在生产的数据,可以使用如下的组成
‒ 数据一:title = 小王,content = 宇宙大帅哥
‒ 数据二:title = 小高,content = 猥琐第一人
既然生产者与消费者是两个独立的线程,那么这两个独立的线程之间就需要有一个数据的保存集中点,那么可以单独定义一个Message类实现数据保存。

class Message{
    private String title ;
    private String content;
    public void setContent(String content){
        this.content = content;
    }
    public void setTitle(String title){
        this.title = title ;
    }
    public String getContent(){
        return this.content ;
    }
    public String getTitle(){
        return this.title;
    }
}
class Producer implements Runnable{
    private Message msg ;
    public Producer(Message msg){
        this.msg = msg ;
    }
    @Override
    public void run(){
        for(int x =0;x <100 ;x++){
            if(x%2 == 0){
                this.msg.setTitle("小王");
                this.msg.setContent("宇宙大帅哥");
            }else{
                this.msg.setTitle("小高");
                this.msg.setContent("猥琐第一人,常态保持");
            }
        }
    }
}
class Consumer implements Runnable{
    private Message msg;
    public Consumer(Message msg){
        this.msg = msg ;
    }
    @Override
    public void run(){
        for(int x =0;x <100 ;x++){
            System.out.println(this.msg.getTitle() + "- " + this.msg.getContent());
        }
    }
}

        Message msg  = new Message() ;
        new Thread(new Producer(msg)).start(); // 启动生产者线程
        new Thread(new Consumer(msg)).start();//启动消费者线程

通过整个代码的执行会发现此时有两个主要问题:
‒ 问题一:数据不同步
‒ 问题二:生产一个取走一个,但是发现有重复生产和重复取出问题

程序开发先考虑基础模型,然后依据基础模型进行改变,很难保证一次性解决问题,这是不可能的
项目代码都是需要分析和设计的。

同步问题的解决

如果要解决问题,首先要解决的就是数据同步的处理问题,如果要想解决数据同步最简单的做法是使用synchronized定义代码块或同步方法,于是这个时候对于同步的处理就可以直接在Message类中完成。

class Message{
    private  String title ;
    private String content;
    public synchronized void set(String title,String content){
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        this.title = title;
        this.content = content ;
    }
    public String get(){
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        return this.title +"  -  " + this.content ;
    }
}

在进行同步处理的时候需要有一个同步的处理对象,那么此时肯定要将同步操作交给Message类处理是最合适的。这个时候发现数据已经可以保持正常的保持一致了,但是对于重复操作的问题依然存在。

利用Object类解决重复操作的问题

要想解决生产者与消费者的问题,那么最好解决方案就是使用等待与唤醒机制。而对于等待与唤醒的机制主要依靠的是Object类中提供的方法处理的:
‒ 等待机制
‒ 死等:public final void wait​() throws InterruptedException
‒ 设置等待时间:public final void wait​(long timeout) throws InterruptedException
‒ (大部分情况下选择)设置等待时间:public final void wait​(long timeout, int nanos) throws InterruptedException
‒ 唤醒第一个等待线程:public final void notify​()
‒ 唤醒全部等待线程:public final void notifyAll​()
如果此时有若干个等待线程,那么notify()表示的是唤醒第一个等待的,而其他的线程继续等待,而notifyAll()表示会唤醒所有等待的线程,哪个线程的优先级高就有可能先执行
对于当前的问题主要的解决应该通过Message类完成处理.


class Message{
    private  String title ;
    private String content;
    private boolean flag = true ;// 表示生产或消费的形式
    // flag = true :允许生产,但是不允许消费
    // flag = false :  允许消费,但是不允许生产
    public synchronized void set(String title,String content){
        if(this.flag == false){ // 无法进行生产,应该等待被消费
            try{
                super.wait();
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();;
        }
        this.title = title;
        this.content = content ;
        this.flag = false ; // 已经生产过了
        super.notify(); // 唤醒等待的线程
    }
    public synchronized String get(){
        if(this.flag == true){ // 还未生产,需要等待
            try {
                super.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        try{
            return this.title +"  -  " + this.content ;
        }finally{
            this.flag = true ; //继续生产
            super.notify(); //唤醒等待线程
        }
    }
}

这种处理形式就是在进行多线程开发过程之中最原始的处理方案,整个的等待,同步,唤醒机制都由开发者自行通过原生代码实现控制。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值