生产者消费者问题

14、生产者消费者问题

14.1、描述

  1. 系统中有一组生产者进程和一组消费者进程,生产者进程每次生产一个产品放入缓冲区,消费者进程每次从缓冲区中取出一个产品并使用。(注: 这里的“产品”理解为某种数据)
  2. 生产者、消费者共享一个初始为空、大小为n的缓冲区。
  3. 只有缓冲区没满时,生产者才能把产品放入缓冲区,否则必须等待。
  4. 只有缓冲区不空时,消费者才能从中取出产品,否则必须等待
  5. 缓冲区是临界资源,各进程必须互斥地访问
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

14.2、分析

  1. 缓冲区是一个临界资源,各个进程必须互斥地访问。
  2. 当缓冲区满的时候,生产者必须要等消费者从缓冲区取走产品之后才能继续生产。(一前一后)。
  3. 当缓冲区空的时候,消费者必须要等生产者将产品放入缓冲区之后才能继续进行消费。(一前一后)。
    在这里插入图片描述
    在这里插入图片描述
  4. 生产者和消费者缓冲区互斥访问是互斥关系,同时生产者和消费者又是一个相互协作的关系,只有生产者生产之后,消费者才能消费,它们也是同步关系
  5. 根据各进程的操作流程确定P、V操作的大致顺序。
    生产者每次要消耗(P)一个空闲缓冲区,并生产(V)一个产品。
    消费者每次要消耗(P)一个产品,并释放一个空闲缓冲区(V)。
    往缓冲区放入/取走产品需要互斥。
  6. 设置信号量。设置需要的信号量,并根据题目条件确定信号量初值。( 互斥信号量初值一般为1,同步信号量的初始值要看对应资源的初始值是多少)
    在这里插入图片描述

14.3、实现

  1. 生产者在生产之前要检查缓冲区,需要消耗一个缓冲区,进行一个P操作。同时生产之后要对产品进行一个V操作。此时增加一个产品。
  2. 消费者在消费之前,要进行一个对产品的P操作,需要消费一个产品;从缓冲区取走一个产品之后要对缓冲区资源进行一个V操作,将缓冲区的一个资源恢复。
  3. 缓冲区是临界资源,各个线程必须互斥进行访问。(生产者在放产品进入缓冲区以及消费者从缓冲区取产品)。
    在这里插入图片描述
  • 实现互斥的P操作一定要在实现同步的P操作之后。
    在这里插入图片描述

14.4、总结

在这里插入图片描述

14.5、Java版的生产者消费者问题

import java.util.Scanner;

/**
 * @author: Laibaijiang
 * @date: 2022/2/11 13:19
 * @description:
 */
public class ProducerConsumer {
    public static void main(String[] args) {
        int producer,consumer;
        Scanner sc=new Scanner(System.in);
        System.out.print("请输入生产者数目:");
        producer=sc.nextInt();//输入生产者数量
        System.out.print("请输入消费者数目:");
        consumer=sc.nextInt();//输入消费者数量
        for(int i=0;i<producer;i++)
        {
            new Thread(new Producer(), "生产者" + Integer.toString(i) + "号").start();//创建生产者线程并开启
        }

        for(int j=0;j<consumer;j++)
        {
            new Thread(new Consumer(), "消费者" + Integer.toString(j) + "号").start();//创建消费者线程并开启
        }
    }

}
class Global
{
    public static Semaphore empty = new Semaphore(3);//空闲缓冲区初始化为三
    public static Semaphore full = new Semaphore(0);//满缓冲区初始化为空
    public static Semaphore mutex = new Semaphore(1);//临界区互斥信号量
    public static int count = 0;//count用于缓冲区中的进程进行计数
    //定时等待
    public static void timingwait()
    {
        try
        {
            Thread.sleep(2000);//Thread.Sleep()方法用于将当前线程休眠一定时间 时间单位是ms,1s=1000ms
        }catch(InterruptedException e)//当使用java.lang.Thread类的sleep方法时,可能会导致线程阻塞,需要抛出InterruptedException(中断异常)异常
        {
            e.printStackTrace();
        }
    }
}
//生产者
class Producer implements Runnable//Runnable接口创建新线程
{
    @Override
    public void run()//Runnable 接口可以被任何想要被一个线程运行的接口继承实现;继承 Runnable 接口的类必须有一个 run() 方法
    {
        Global.timingwait();
        System.out.println(Thread.currentThread().getName() + "  生产出一个商品...");//Thread.currentThread().getName()获得当前执行的线程
        Global.empty.P();//获取空缓冲区单元
        Global.mutex.P();//进入临界区
        Global.timingwait();
        System.out.println(Thread.currentThread().getName() + "  将产品放入缓冲区--缓冲区剩余 " + (++Global.count) + " 个产品");
        Global.mutex.V();//离开临界区,释放信号量
        Global.full.V();//满缓冲区数加一
    }
}
//消费者
class Consumer implements Runnable
{
    @Override
    public void run()
    {
        Global.timingwait();
        Global.full.P();//获取满缓冲区单元
        Global.mutex.P();//进入临界区
        Global.timingwait();
        System.out.println(Thread.currentThread().getName() + "  从缓冲区取出一个产品--缓冲区剩余 "+ (--Global.count) + " 个产品");
        Global.mutex.V();//离开临界区,释放互斥信号量
        Global.empty.V();//空缓冲区加一
        System.out.println(Thread.currentThread().getName() + "  消费一个商品...");
    }
}
//信号量
class Semaphore
{
    public int value;
    public Semaphore(int value)
    {
        super();
        this.value=value;
    }
    //P操作
    public synchronized final void P()//使用synchronized修饰的方法,叫做同步方法,保证A线程执行该方法的时,其他线程只能在方法外等着.
    {//被final修饰的方法是一个最终方法,不能被重写,重写会报错
        value--;
        if(value<0)
        {
            try
            {
                this.wait();//当缓冲区已满/空时,生产者或消费者线程停止自己的执行,释放锁,使自己处于等待状态,让其它线程执行
            }catch(InterruptedException e)//当使用java.lang.Thread类的 wait方法时,可能会导致线程阻塞,需要抛出InterruptedException(中断异常)异常
            {
                e.printStackTrace();
            }
        }
    }
    //V操作
    public synchronized final void V()
    {
        value++;
        if(value<=0)
        {
            this.notify();//当生产者或消费者向缓冲区放入或取出一个产品时,向其他等待的线程发出通知,同时释放锁,使自己处于等待状态,让其它线程执行。
        }
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值