Java教程

多线程之生产者消费者问题案例

本文主要是介绍多线程之生产者消费者问题案例,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
  • 生产者消费者模式概述
    • 生产者消费者模式是一个经典的多线程协作的模式,弄懂生产者消费者问题能够让我们对多线程编程的理解更加深刻
    • 所谓的生产者消费者问题,实际上主要是包含了两类线程:
      • 一类是生产者线程用于生产数据
      • 一类是消费者线程用于消费数据
    • 为了解耦生产者和消费者的关系,通常会采用共享的数据区域,就像是一个仓库
      • 生产者生产数据之后直接放置在共享数据区中,并不需要关心消费者的行为

    • 为了体现生产和消费过程中等待和唤醒,Java就提供了几个方法供我们使用,这几个方法在Object类中
    • Object类的等待和唤醒方法:

  • 生产者消费者案例
    • 生产者消费者案例中包含的类:
      • 奶箱类(Box):定义一个成员变量,表示第x瓶奶,提供存储牛奶和获取牛奶的操作
      • 生产者类(Producer):实现Runnable接口,重写run()方法,调用存储牛奶的操作
      • 消费者类(Customer):实现Runnable接口,重写run()方法,调用获取牛奶的操作
      • 测试类(BoxDemo):里面有main()方法,main方法中的代码步骤如下
        • 创建奶箱对象,这是共享数据区域
        • 创建生产者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作
        • 创建消费者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用获取牛奶的操作
        • 创建两个线程对象,分别把生产者对象和消费者对象作为构造方法参数传递
        • 启动线程
        • 注意:在Box类中使用的If判断一定不能混淆,否则程序会陷入死循环。

Box类

package MikeBox;
///奶箱类(Box):定义一个成员变量,表示第x瓶奶,提供存储牛奶和获取牛奶的操作
public class Box {
    private int milk;

    //定义一个成员变量,表示奶箱的状态
    private boolean stats = false;

    //提供存储牛奶和获取牛奶的操作
    public synchronized void put(int milk){
        //如果是牛奶,等待消费
        if (stats){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //如果没有牛奶,就生产牛奶
        this.milk = milk;
        System.out.println("送奶工将第" + this.milk + "瓶奶放入奶箱");

        //生产完毕之后,修改奶箱状态
        stats = true;

        //唤醒其他等待的线程
        notify();
    }

    public synchronized void get(){
        //如果没有牛奶,等待生产
        if (stats != true){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //如果有牛奶,就消费牛奶
        System.out.println("用户拿到第" +this.milk +"瓶奶");

        //消费完毕之后,修改奶箱状态
        stats = false;

        //唤醒其他等待线程
        notify();
    }
}

Producer类

package MikeBox;

public class Producer implements Runnable{

    private Box b;

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

Customer类

package MikeBox;

public class Customer implements Runnable {

    private Box b;

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

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

测试代码

package MikeBox;
/*
            生产者消费者案例中包含的类:
                    奶箱类(Box):定义一个成员变量,表示第x瓶奶,提供存储牛奶和获取牛奶的操作
                    生产者类(Producer):实现Runnable接口,重写run()方法,调用存储牛奶的操作
                    消费者类(Customer):实现Runnable接口,重写run()方法,调用获取牛奶的操作
                    测试类(BoxDemo):里面有main()方法,main方法中的代码步骤如下
                            创建奶箱对象,这是共享数据区域
                            创建生产者类(Producer):实现Runnable接口,重写run()方法,调用存储牛奶的操作
                            创建消费者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用获取牛奶的操作
                            创建两个线程对象,分别把生产者对象和消费者对象作为构造方法参数传递
                            启动线程

*/
public class BoxDemo {
    public static void main(String[] args) {
        //奶箱类(Box):定义一个成员变量,表示第x瓶奶,提供存储牛奶和获取牛奶的操作
        Box b = new Box();

        //创建生产者类(Producer):实现Runnable接口,重写run()方法,调用存储牛奶的操作
        Producer p = new Producer(b);

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

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

        //启动线程
        t1.start();
        t2.start();
    }
}

 

这篇关于多线程之生产者消费者问题案例的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!