快速学习生产者和消费者模型

本文深入解析生产者消费者模型,阐述其核心概念:生产者、消费者及缓冲区。通过两种实现方式,lock和原子类结合阻塞队列,展示如何在多线程环境下确保数据一致性。

快速学习生产者和消费者模型

一、学习生产者和消费这模型之前,你要了解三个概念,生产者,消费者和缓冲区。
1、生产者:产生数据
2、消费者:使用数据
3、缓冲区,存储数据
二、生产者生产数据会保存在缓冲区,消费者会在缓冲区里取数据进行消费。
注意:当缓冲区填满时,生产者不可生产数据,当缓冲区为空时,消费者不可取数据。数据不可重复生产也不可重复获取,这里以id来区分(id 以自增的方式生成)
三,代码

Book为产品,有三个字段,分别是id,name,price。

方式一、lock的方式

public class ProducerAndConsumerByManyToMany {

    private final ReentrantLock lock = new ReentrantLock();
    private final Condition consumerCondition = lock.newCondition();
    private final Condition producerCondition = lock.newCondition();

    private int id = 1;

    private final int MAX_QUE = 10;
    LinkedList<Book> list = new LinkedList<>();

    class Consumer implements Runnable{

        @Override
        public void run() {
            while (!Thread.currentThread().isInterrupted()){
                lock.lock();
                try {
                    while (list.isEmpty()){
                        System.out.println("queue is empty...");
                        consumerCondition.await();
                    }
                    mySleep(200);
                    System.out.println(list.remove());
                    mySleep(100);
                    producerCondition.signal();
                } catch (Exception e){
                    System.out.println(e.getMessage());
                } finally {
                    lock.unlock();
                }
            }
        }
    }
    class Producer implements Runnable{

        @Override
        public void run() {
            while (!Thread.currentThread().isInterrupted()){
                lock.lock();
                try {
                    while (list.size()==MAX_QUE){
                        System.out.println("queue is full...");
                        producerCondition.await();
                    }
                    mySleep(200);
                    list.add(new Book(id+++"","A","¥99.00"));
                    mySleep(100);
                    consumerCondition.signal();
                } catch (Exception e){
                    System.out.println(e.getMessage());
                } finally {
                    lock.unlock();
                }
            }
        }
    }
    private void mySleep(long time){
        try {
            Thread.sleep(time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        ProducerAndConsumerByManyToMany mtm = new ProducerAndConsumerByManyToMany();
        new Thread(mtm.new Producer()).start();
        new Thread(mtm.new Producer()).start();
        new Thread(mtm.new Producer()).start();
        new Thread(mtm.new Consumer()).start();
        new Thread(mtm.new Consumer()).start();
    }

注意:await条件为什么要用while而不是if,原因如下
因为 会有多个消费者或者生产者的情况,以消费者为例:当一个消费者获得lock,来到await循环条件,此时缓冲区(链表)为空,只能等待并释放锁,第二个消费者获得锁,碰巧也为空,也只能等待并释放锁。次时如果生产者生产了一条数据,并唤醒了所有的消费者。如果为if的话,被唤醒的并不会继续做判空,一个消费者获得了锁并消费了数据,释放锁,另一个消费者也获得了锁,此时缓冲区为空,却做了取数据的操作,出现了数据不一致

方式二、通过原子类和阻塞队列的方式

public class ProducerAndConsumerByAtomic {

    private final AtomicInteger id = new AtomicInteger(1);
    private final int MAX_PRODUCTION = 30;
    private final BlockingQueue<Book> queue = new ArrayBlockingQueue<>(3);

    class Consumer implements Runnable{

        @Override
        public void run() {
            while (!Thread.currentThread().isInterrupted()){
                try {
                    System.out.println(queue.take());
                    mySleep(100);
                } catch (Exception e){
                    System.out.println(e.getMessage());
                }
            }
        }
    }
    class Producer implements Runnable{

        @Override
        public void run() {
            int a;
            while (!Thread.currentThread().isInterrupted()&&(a = id.getAndIncrement())<=MAX_PRODUCTION){
                try {
                    queue.put(new Book(a+"","活着","63¥"));
                    mySleep(200);
                } catch (Exception e){
                    System.out.println(e.getMessage());
                }
            }
        }
    }

    private void mySleep(long time){
        try {
            Thread.sleep(time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        ProducerAndConsumerByAtomic Pa = new ProducerAndConsumerByAtomic();

        new Thread(Pa.new Producer()).start();
        new Thread(Pa.new Producer()).start();
        new Thread(Pa.new Consumer()).start();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值