首页 > 技术文章 > java基础-生产者消费者

nanao 2021-08-12 00:44 原文

生产者消费者模式概念:

生产者消费者模式是一个十分经典的多线程协作的模式,弄懂生产者消费者问题能够让我们对多线程编程的理解更加深刻。所谓生产者消费者的问题。实际上主要是包含了两类线程

1)一类是生产者线程用于生产数据

2)一类是消费者用于消费数据

为了解耦生产者和消费者的关系,通常会采用共享的数据区域,就像是一个仓库

生产者生产数据之后直接放置在共享数据区中,并不需要关心消费者的行为;消费者只需要从共享数据区中去获取数据,并不需要关心生产者的行为

生产者消费者模式概述:

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

void wait() 导致当前线程等待,直到另一个线程调用该对象的notify()方法或者 notifyAll()方法

notify() 唤醒正在等待对象监视器的单个线程

notifyAll() 唤醒正在等待对象监视器的所有线程**

例子:生产者-厨师 消费者-客人,定义桌子类存放牛排

厨师煎牛排,桌子上一块都没有 客人需要等待

桌子上牛排满了,厨师不需要生产 需要客人去拿

厨师在煎牛排过程中,如果没有煎完,客人不能去拿

客人没有拿完,不能把客人赶走

生产者消费者代码例子:

public class Table {
    LinkedList<Object> list = new LinkedList<>();
    private static final int Max=100;

    //存储产品
    public synchronized void store(String product){
        //如果仓库已满 生产者等待;
        while (list.size()>Max){
            try {
                this.wait(); //wait();notify()这两个在同步代码块中,由锁对象调用
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName()+"++存储了"+product);//把产品存进去
        list.offer(product);

    }
    //取产品
    public synchronized void take(){
        //判断仓库是否为空,当仓库空时需要等待
        while (list.size() <= 0){
            try{
                this.wait();
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
        Object product = list.poll();//把前面的产品取出来
        System.out.println(Thread.currentThread().getName()+"--消费了"+product);
        //通知生产者继续生产
        this.notify();
    }
}


定义生产者

public class Product extends Thread {
    private Table table;
    public Product(Table table) {
        super();
        this.table = table;
    }
    @Override
    public void run(){
        for(int i=0;i<30;i++){
            String product = "产品编号:"+new Random().nextInt(100);
            table.store(product);
        }
    }
}

定义消费者

public class ConsumerThread extends Thread {
    private Table table;
    public ConsumerThread(Table table) {
        super();
        this.table = table;
    }
    @Override
    public void run(){
        for(int i=0;i<30;i++){
            table.take();
        }
    }
}

测试类:

class test{
    public static void main(String[] args) {
        //创建桌子
        Table table = new Table();
        //创建3个生产者线程模拟三个人
        Product p1= new Product(table);
        Product p2= new Product(table);
        Product p3= new Product(table);
        p1.setName("张三");
        p2.setName("李四");
        p3.setName("王五");
        p1.start();
        p2.start();
        p3.start();

        ConsumerThread c1 = new ConsumerThread(table);
        ConsumerThread c2 = new ConsumerThread(table);
        ConsumerThread c3 = new ConsumerThread(table);
        c1.setName("吃货1号");
        c2.setName("吃货2号");
        c3.setName("吃货3号");
        c1.start();
        c2.start();
        c3.start();
    }
}

例子2:两个线程交替打印奇数和偶数

public class PrintNum {
    private int num=0;
    //打印奇数
    public synchronized void printJi(){
        //当num是偶数时需要等待
        while (num % 2==0){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
        System.out.println(Thread.currentThread().getName()+":"+num);
        num++;
        //通知打印偶数
        this.notify();
    }
    //打印偶数
    public synchronized void printOu(){
        //当num是奇数时需要等待
        while (num % 2==1){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
        System.out.println(Thread.currentThread().getName()+":"+num);
        num++;
        //通知打印奇数
        this.notify();
    }
}
class test09{
    public static void main(String[] args) {
        PrintNum printNum = new PrintNum();
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true){
                    printNum.printJi();
                }
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true){
                    printNum.printOu();
                }
            }
        }).start();
    }
}

推荐阅读