线程之生产者消费者案例-送奶

生产者和消费者问题是线程模型中的经典问题,生产者和消费者在同一时间段共用同一个存储空间,这个存储空间是一个缓冲区的仓库,生产者可以将产品放入仓库,消费者可以从仓库中取出产品。

生产者/消费者模型是基于等待/通知机制,主要关注以下几点:

生产者生产的时候消费者不能消费
消费者消费的时候生产者不能生产
缓冲区空时消费者不能消费
缓冲区满时生产者不能生产

主要优点:

解耦。因为多了一个缓冲区,所以生产者和消费者并不直接相互调用,这一点很容易想到,这样生产者和消费者的代码发生变化,都不会对对方产生影响,这样其实就把生产者和消费者之间的强耦合解开,变为了生产者和缓冲区/消费者和缓冲区之间的弱耦合
通过平衡生产者和消费者的处理能力来提高整体处理数据的速度,这是生产者/消费者模型最重要的一个优点。如果消费者直接从生产者这里拿数据,如果生产者生产的速度很慢,但消费者消费的速度很快,那消费者就得占用CPU的时间片白白等在那边。有了生产者/消费者模型,生产者和消费者就是两个独立的并发体,生产者把生产出来的数据往缓冲区一丢就好了,不必管消费者;消费者也是,从缓冲区去拿数据就好了,也不必管生产者,缓冲区满了就不生产,缓冲区空了就不消费,使生产者/消费者的处理能力达到一个动态的平衡。
生产者消费者案例:
    1.奶箱类(Box):定义一个成员变量,表示第x瓶奶,提供存储和获取牛奶的操作
    2.生产者(Producer):实现Runnable接口,重写run()方法,调用存储牛奶的操作
    3.消费者(Customer):实现Runnable接口,重写run()方法,调用存储牛奶的操作
    4.测试类(SendMilkDemo):里面有main方法,main方法中的代码步骤如下:
        a.创建奶箱对象,把奶箱作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作
        b.创建生产者对象,把奶箱作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作
        c.创建消费者对象,把奶箱作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作
        d.创建2个线程对象,分别把生产者对象和消费者对象作为构造方法参数传递

这里使用了wait()等待 和 notify()唤醒 方法。
测试类:
package Mymodifier.testcode.src.Thread;

public class SendMilkDemo
{
    public static void main(String[] strings)
    {
/*
    生产者消费者案例:
        1.奶箱类(Box):定义一个成员变量,表示第x瓶奶,提供存储和获取牛奶的操作
        2.生产者(Producer):实现Runnable接口,重写run()方法,调用存储牛奶的操作
        3.消费者(Customer):实现Runnable接口,重写run()方法,调用存储牛奶的操作
        4.测试类(SendMilkDemo):里面有main方法,main方法中的代码步骤如下:
            a.创建奶箱对象,把奶箱作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作
            b.创建生产者对象,把奶箱作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作
            c.创建消费者对象,把奶箱作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作
            d.创建2个线程对象,分别把生产者对象和消费者对象作为构造方法参数传递
*/

        //创建奶箱对象,把奶箱作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作
        Box b = new Box();

        //创建生产者对象,把奶箱作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作
        Producer p = new Producer(b);
        //创建消费者对象,把奶箱作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作
        Comsumer c = new Comsumer(b);

        //创建2个线程对象,分别把生产者对象和消费者对象作为构造方法参数传递
        Thread p2 = new Thread(p,"生产者");
        Thread c2 = new Thread(c,"消费者");

        //启动线程
        p2.start();
        c2.start();
    }
}

奶箱类:

package Mymodifier.testcode.src.Thread;

public class Box
{
    //定义一个成员变量,表示第x瓶奶
    private int milk;
    //创建牛奶状态(默认为false)
    private boolean state = false;

    //存储牛奶数量(加了同步关键字才能使用wait(等待)和notify/All(唤醒))
    public synchronized void put(int milk) {
        //如果牛奶状态为true
        if(state)
        {
            //则进入等待
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        this.milk = milk;
        //如果有牛奶,就消费牛奶
        System.out.println("送奶工将第" + this.milk + "瓶放入奶箱");
        //牛奶状态设置为true
        state = true;
        //唤醒全部等待线程
        notifyAll();
    }

    //获取牛奶数量
    public synchronized void get() {
        //如果牛奶状态为false
        if (!state)
        {
            //则进入等待
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //如果没有牛奶,就生产牛奶
        System.out.println("用户拿到第" + this.milk + "瓶奶");
        //牛奶状态设置为true
        state = false;
        //唤醒全部等待线程
        notifyAll();
    }


}

生产者类(送奶工):

package Mymodifier.testcode.src.Thread;

public class Producer implements Runnable
{

    private Box b;

    public Producer(Box b)
    {
        this.b = b;
    }
    @Override
    public void run() {
        for(int i = 1; i < 6; i++)
        {
            b.put(i);
        }
    }
}

消费者类:

package Mymodifier.testcode.src.Thread;

public class Comsumer implements Runnable {
    private Box b;

    public Comsumer(Box b)
    {
        this.b = b;
    }

    @Override
    public void run()
    {
        while(true)
        {
            b.get();
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值