(4)生产者-消费者模型

生产者和消费者基本程序模型

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

程序实现:

​ 可以将生产者和消费者定义为两个独立的线程类对象,两个独立的线程之间需要有一个数据的保存集中点,那么可以单独定义一个Message类实现数据的保存。

class Message{
    private String title;
    private String content;
    public void setTitle(String title){
        this.title=title;
    }
    public void setContent(String content){
        this.content=content;
    }
    public String getTitle(){
        return this.title;
    }
    public String getContent(){
        return this.content;
    }
}
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("产品A");
                this.msg.setContent("AAAAA");

            }
            else{
                this.msg.setTitle("产品B");
                this.msg.setContent("BBBBBB");
            }
        }
    }
}
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());
        }
    }
}
public class ProductAndConsumer {
    public static void main(String[] args) {
        Message message = new Message();
        new Thread(new Producer(message)).start();
        new Thread(new Consumer(message)).start();

    }
}

​ 通过代码的执行会发现此时有两个主要的问题:

  1. 数据不同步了
  2. 生产一个取走一个,但是会发现有重复生产和重复取出的问题。

解决同步问题

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

class Message{
    private String title;
    private String content;
    public synchronized void set(String title,String content) throws InterruptedException {
        this.title=title;
        Thread.sleep(100);
        this.content=content;
    }
    public synchronized  String  get() throws InterruptedException {
        Thread.sleep(10);
        return this.title+"-"+this.content;
    }

}
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){
                try {
                    this.msg.set("产品A","AAAAA");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
            else{
                try {
                    this.msg.set("产品B","BBBBB");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
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++){
            try {
                System.out.println(this.msg.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class ProductAndConsumer {
    public static void main(String[] args) {
        Message message = new Message();
        new Thread(new Producer(message)).start();
        new Thread(new Consumer(message)).start();

    }
}

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

利用Object类解决重复操作

​ 如果想要解决生产者和消费者问题,那么最好的解决方案就是使用等待与唤醒机制,而对于等待与唤醒的造作机制,主要依靠的是Object类中提供的方法处理的。

  • 等待机制

    //死等
    public final void wait() throws InterruptedException
    //设置等待时间
    public final void wait(long timeout) throws InterruptedException
    //设hi在等待时间
    public final void wait(long timeout, int nanos) throws InterruptedException
    
  • 唤醒第一个等待线程:

    public final void notify()
    
  • 唤醒全部等待线程:

    //唤醒全部的线程,哪个线程的优先级高就有可能先执行
    public final void notifyAll()
    

​ 对于当前问题的解决应该通过Message类完成处理

class Message{
    private String title;
    private String content;
    /**
     * 表示生产或消费的形式
     * flag=true 允许生产 不允许消费
     * flag=false 允许消费 不允许生产
     */
    private boolean flag=true;
    public synchronized void set(String title,String content) throws InterruptedException {
        if(!this.flag){//无法进行生产,应该等待被消费
            super.wait();
        }
        this.title=title;
        Thread.sleep(100);
        this.content=content;
        this.flag=false;//已经生产过啦
        super.notify();//唤醒等待的线程
    }
    public synchronized  String  get() throws InterruptedException {
        if(this.flag){//还未生产 需要等待
            super.wait();
        }
        Thread.sleep(10);
        try{
        return this.title+"-"+this.content;
        }finally{ //不管如何都要执行
            this.flag=true;//可以继续进行生产
            super.notify(); //唤醒等待线程
        }


    }

}
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){
                try {
                    this.msg.set("产品A","AAAAA");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
            else{
                try {
                    this.msg.set("产品B","BBBBB");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
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++){
            try {
                System.out.println(this.msg.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
public class ProductAndConsumer {
    public static void main(String[] args) {
        Message message = new Message();
        new Thread(new Producer(message)).start();
        new Thread(new Consumer(message)).start();

    }
}

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

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值