操作系统 —— 生产者消费者问题JAVA代码实现 [有比较low的界面]

2023-05-16

生产者消费者问题JAVA代码说明文档

一、生产者消费者问题说明

​ 生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。参考地址

​ 要解决该问题,就必须让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。通常采用进程间通信的方法解决该问题,常用的方法有信号灯法等。如果解决方法不够完善,则容易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己。该问题也能被推广到多个生产者和消费者的情形。参考地址

二、问题解决

解决核心:
①生产者—消费者之间的同步关系表现为: 一旦缓冲池中所有缓冲区均装满产品时,生产者必须等待消费者提供空缓冲区;一旦缓冲池中所有缓冲区全为空时,消费者必须等待生产者提供缓冲区。
②生产者—消费者之间还有互斥关系: 由于缓冲池是临界资源,所以任何进程在对缓冲区进行存取操作时都必须和其他进程互斥进行。

伪代码:

semaphore mutex=1; //临界区互斥信号量
semaphore empty=n;  //空闲缓冲区
semaphore full=0;  //缓冲区初始化为空
producer ()//生产者进程 
{
    while(1)
    {
        produce an item in nextp;  //生产数据
        P(empty);  //获取空缓冲区单元
        P(mutex);  //进入临界区.
        add nextp to buffer;  //将数据放入缓冲区
        V(mutex);  //离开临界区,释放互斥信号量
        V(full);  //满缓冲区数加1
    }
}

consumer ()//消费者进程
{
    while(1)
    {
        P(full);  //获取满缓冲区单元
        P(mutex);  // 进入临界区
        remove an item from buffer;  //从缓冲区中取出数据
        V(mutex);  //离开临界区,释放互斥信号量
        V(empty) ;  //空缓冲区数加1
        consume the item;  //消费数据
    }
}

JAVA代码:

/**   Producer.java   **/
public class Producer extends Thread implements Runnable {
    private Cache cache;
    public Producer(Cache cache){
        this.cache = cache;
    }

    @Override
    public void run() {
        while (true){
            try{
                cache.produce();
                Thread.sleep(cache.produce_speed);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}
/**   Consumer.java   **/
public class Consumer extends Thread implements Runnable{
    private Cache cache;
    public Consumer(Cache cache){
        this.cache = cache;
    }

    @Override
    public void run() {
        while (true){
            try{
                cache.consume();
                Thread.sleep(cache.consume_speed);
            }catch (InterruptedException e){
                e.printStackTrace();
            }
        }
    }
}
/**   Cache.java   **/
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Cache  {
    public int SIZE = 100;  //容器值
    public int count;   //当前资源的数量
    public Lock lock;
    private Condition notFull;
    private Condition notEmpty;

    int produce_speed = 0; //生产者速度
    int consume_speed = 0; //消费者速度

    public String producer_print = "";
    public String consumer_print = "";

    public Cache(){
        //构造方法
        this.count = 0;
        this.lock = new ReentrantLock();
        this.notEmpty = lock.newCondition();
        this.notFull = lock.newCondition();
    }

    //生产资源
    public void produce(){
        try {
            lock.lock(); // 开启锁
            while (count == SIZE) {
                try {
                    System.out.println("容器已满,生产者阻塞");
                    notFull.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            count++;
            producer_print = "生产者生产了一个,当前数量为:" + count +"\n"+ "生产者线程为:" + Thread.currentThread().getName();
            System.out.println(producer_print);
            notEmpty.signal();  // 唤醒其他等待的线程
        }finally {
            lock.unlock();
        }


    }

    //消费资源
    public void consume(){
        try {
            lock.lock();
            while (count == 0) {
                try {
                    System.out.println("容器已满,消费者阻塞");
                    notEmpty.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            count--;
            consumer_print = "消费者消费了一个,当前数量为:" + count + '\n'+ "消费者线程为:" + Thread.currentThread().getName();
            System.out.println(consumer_print);
            notFull.signal();  // 唤醒其他等待的线程
        }finally {
            lock.unlock();  // 释放锁
        }
    }

}
/**   Main.java   **/
import javax.swing.*;
import javax.swing.border.TitledBorder;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class Main {

    static String Producer_print ;
    static String Consumer_print ;
    static String Cache_print ;

    public static int is_begin = 0;
    public static int is_end = 0;
    private static long sleep_millis;
    private static int is_start = 0;
    static int producerCount = 0; //生产者数量
    static int consumerCount = 0; //消费者数量


    public static void main(String[] args) throws InterruptedException {

        Cache cache = new Cache();
        Producer p = new Producer(cache);
        Consumer c = new Consumer(cache);

        //页面的创建

        JFrame jFrame = new JFrame();
        jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jFrame.setSize(1300,700);
        jFrame.setTitle("生产者消费者问题");

        //添加 文字标签 字体样式
        Font label_font = new Font("Monospaced",Font.BOLD,20);

        //添加 面板标题 字体样式
        Font Panel_font = new Font("Monospaced",Font.BOLD,18);

        //添加主面板
        JPanel panel = new JPanel();
        panel.setLayout(null);
        jFrame.add(panel);

        //添加左上面板
        JPanel panel_attribute = new JPanel();
        panel_attribute.setLayout(null);
        panel_attribute.setBounds(new Rectangle(60,60,400,250));
        panel_attribute.setBorder(BorderFactory.createTitledBorder(null,"设置基本属性", TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION,Panel_font));
        panel.add(panel_attribute,BorderLayout.EAST);

        //添加输出框(线程运行监控)面板
        JPanel panel_print = new JPanel();
        panel_print.setLayout(null);
        panel_print.setBounds(new Rectangle(500,60,700,500));
        panel_print.setBorder(BorderFactory.createTitledBorder(null,"线程运行监控",TitledBorder.DEFAULT_JUSTIFICATION, TitledBorder.DEFAULT_POSITION,Panel_font));
        panel.add(panel_print,BorderLayout.EAST);

        // 添加 "缓冲区" 标签
        JLabel buffer_label = new JLabel("缓冲区容量:");
        buffer_label.setBounds(40,55,200,40);
        buffer_label.setForeground(Color.black);//设置前景色,默认应该是黑色吧,没有尝试
        buffer_label.setFont(label_font);
        jFrame.getContentPane().add(buffer_label);
        panel_attribute.add(buffer_label);

        // 添加 "生产者" 标签
        JLabel Producer_label = new JLabel("生产者数量:");
        Producer_label.setBounds(40,85,200,40);
        Producer_label.setForeground(Color.black);
        Producer_label.setFont(label_font);
        jFrame.getContentPane().add(Producer_label);
        panel_attribute.add(Producer_label);

        //添加 "消费者" 标签
        JLabel Consumer_label = new JLabel("消费者数量:");
        Consumer_label.setBounds(40,115,200,40);
        Consumer_label.setForeground(Color.BLACK);
        Consumer_label.setFont(label_font);
        jFrame.getContentPane().add(Consumer_label);
        panel_attribute.add(Consumer_label);

        //添加 "生产者生产速度" 标签
        JLabel Producer_speed_label = new JLabel("生产者生产速度:");
        Producer_speed_label.setBounds(40,145,200,40);
        Producer_speed_label.setForeground(Color.BLACK);
        Producer_speed_label.setFont(label_font);
        jFrame.getContentPane().add(Producer_speed_label);
        panel_attribute.add(Producer_speed_label);

        //添加 "消费者消耗速度" 标签
        JLabel Consumer_speed_label = new JLabel("消费者消耗速度:");
        Consumer_speed_label.setBounds(40,175,200,40);
        Consumer_speed_label.setForeground(Color.BLACK);
        Consumer_speed_label.setFont(label_font);
        jFrame.getContentPane().add(Consumer_speed_label);
        panel_attribute.add(Consumer_speed_label);

        //添加 “缓冲区容量” 选择菜单栏
        JComboBox buffer_ComboBox = new JComboBox();
        buffer_ComboBox.addItem(10);
        buffer_ComboBox.addItem(100);
        buffer_ComboBox.addItem(1000);
        buffer_ComboBox.addItem(10000);
        buffer_ComboBox.setBounds(170,64,140,26);
        panel_attribute.add(buffer_ComboBox);


        //添加 "生产者数量" 选择菜单栏
        JComboBox Producer_ComboBox = new JComboBox();
        Producer_ComboBox.addItem(1);
        Producer_ComboBox.addItem(2);
        Producer_ComboBox.addItem(4);
        Producer_ComboBox.addItem(8);
        Producer_ComboBox.addItem(16);
        Producer_ComboBox.addItem(32);
        Producer_ComboBox.setBounds(170,94,140,26);
        panel_attribute.add(Producer_ComboBox);

        //添加 "消费者数量" 菜单选择栏
        JComboBox Consumer_ComboBox = new JComboBox();
        Consumer_ComboBox.addItem(1);
        Consumer_ComboBox.addItem(2);
        Consumer_ComboBox.addItem(4);
        Consumer_ComboBox.addItem(8);
        Consumer_ComboBox.addItem(16);
        Consumer_ComboBox.addItem(32);
        Consumer_ComboBox.setBounds(170,124,140,26);
        panel_attribute.add(Consumer_ComboBox);

        //添加 "生产者速度" 菜单选择栏
        JComboBox Producer_speed_ComboBox = new JComboBox();
        Producer_speed_ComboBox.addItem(10);
        Producer_speed_ComboBox.addItem(100);
        Producer_speed_ComboBox.addItem(1000);
        Producer_speed_ComboBox.addItem(10000);
        Producer_speed_ComboBox.setBounds(210,154,140,26);
        panel_attribute.add(Producer_speed_ComboBox);


        //添加 "消费者速度" 输入文本框
        JComboBox Consumer_speed_ComboBox = new JComboBox();
        Consumer_speed_ComboBox.addItem(10);
        Consumer_speed_ComboBox.addItem(100);
        Consumer_speed_ComboBox.addItem(1000);
        Consumer_speed_ComboBox.addItem(10000);
        Consumer_speed_ComboBox.setBounds(210,184,140,26);
        panel_attribute.add(Consumer_speed_ComboBox);

        //添加 "开始" 按钮
        JButton begin_button = new JButton("开始");
        begin_button.setLocation(60, 360);
        begin_button.setSize(200, 40);
        begin_button.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                // 进行逻辑处理
                is_begin = 1;
                is_end = 0;
            }
        });
        jFrame.getContentPane().add(begin_button);
        panel.add(begin_button);

        //添加 "暂停" 按钮
        JButton cease_button = new JButton("暂停");
        cease_button.setLocation(60, 410);
        cease_button.setSize(200, 40);
        cease_button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // 进行逻辑处理
                is_begin = 0;
                is_end = 1;
            }
        });
        jFrame.getContentPane().add(cease_button);
        panel.add(cease_button);

        //添加 "结束" 按钮
        JButton exit_button = new JButton("结束");
        exit_button.setLocation(60, 460);
        exit_button.setSize(200, 40);
        exit_button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // 进行逻辑处理
                System.exit(0);
            }
        });
        jFrame.getContentPane().add(exit_button);
        panel.add(exit_button);

        //添加进程展示

        // 添加 "生产者" 标签
        JLabel Thread_buffer_label = new JLabel("生产者线程:");
        Thread_buffer_label.setBounds(35,33,200,40);
        Thread_buffer_label.setForeground(Color.black);
        Thread_buffer_label.setFont(label_font);
        jFrame.getContentPane().add(Thread_buffer_label);
        panel_print.add(Thread_buffer_label);

        // 添加 "消费者" 标签
        JLabel Thread_Producer_label = new JLabel("消费者线程:");
        Thread_Producer_label.setBounds(245,33,200,40);
        Thread_Producer_label.setForeground(Color.black);
        Thread_Producer_label.setFont(label_font);
        jFrame.getContentPane().add(Thread_Producer_label);
        panel_print.add(Thread_Producer_label);

        //添加 "缓冲区" 标签
        JLabel Thread_Consumer_label = new JLabel("缓冲区数量:");
        Thread_Consumer_label.setBounds(455,33,200,40);
        Thread_Consumer_label.setForeground(Color.BLACK);
        Thread_Consumer_label.setFont(label_font);
        jFrame.getContentPane().add(Thread_Consumer_label);
        panel_print.add(Thread_Consumer_label);

        //生产者线程展示
        JTextArea Thread_Producer_TextArea = new JTextArea();
        Thread_Producer_TextArea.setText(Producer_print+Thread_Producer_TextArea.getText());
        Thread_Producer_TextArea.setText("");
        Thread_Producer_TextArea.setBounds(35,70,200,400);
        panel_print.add(Thread_Producer_TextArea);

        //消费者线程展示
        JTextArea Thread_Consumer_TextArea = new JTextArea();
        Thread_Consumer_TextArea.setText(Consumer_print+'\n'+Thread_Consumer_TextArea.getText());
        Thread_Consumer_TextArea.setText("");
        Thread_Consumer_TextArea.setBounds(245,70,200,400);
        panel_print.add(Thread_Consumer_TextArea);

        //缓存区线程展示
        JTextArea Thread_cache_TextArea = new JTextArea();
        Thread_cache_TextArea.setText(Cache_print+"\n"+Thread_cache_TextArea.getText());
        Thread_cache_TextArea.setText("");
        Thread_cache_TextArea.setBounds(455,70,200,400);
        panel_print.add(Thread_cache_TextArea);


        jFrame.setContentPane(panel);
        jFrame.setVisible(true);

        while(true){

            Producer_print = cache.producer_print;
            Consumer_print = cache.consumer_print;
            Cache_print = "缓存区的容量为:"+cache.count;

            cache.SIZE = (Integer)buffer_ComboBox.getSelectedItem();
            producerCount = (Integer)Producer_ComboBox.getSelectedItem();
            consumerCount = (Integer)Consumer_ComboBox.getSelectedItem();
            cache.produce_speed = (Integer)Producer_speed_ComboBox.getSelectedItem();
            cache.consume_speed = (Integer)Consumer_speed_ComboBox.getSelectedItem();

            Thread_Producer_TextArea.setText(Producer_print+"\n"+Thread_Producer_TextArea.getText());
            Thread_Consumer_TextArea.setText(Consumer_print+"\n"+Thread_Consumer_TextArea.getText());
            Thread_cache_TextArea.setText(Cache_print+"\n"+Thread_cache_TextArea.getText());

            if(is_begin ==1 && is_end == 0 && is_start == 0) {
                is_start = 1;
                for (int i = 0; i < producerCount; i++) {
                    new Thread(p).start();
                }
                for (int i = 0; i < consumerCount; i++) {
                    new Thread(c).start();
                }
            }
            if (is_begin ==1 && is_end == 0 && is_start ==1){
                sleep_millis = 0;
                Thread.sleep(sleep_millis);
            }
            if(is_begin == 0 && is_end ==1){
                sleep_millis = 1000;
                Thread.sleep(sleep_millis);
            }

            Thread.currentThread().sleep(1000); //延时使得文本框中展示不会太快
        }


    }
}

Producer.java 、 Consumer.java 、 Cache.java 、 Main.java 共四部分实现生产者消费者问题
Producer.java 、 Consumer.java 、 Cache.java 三部分实现生产者消费者线程问题
Main.java 部分为验证执行和界面制作

实现功能:
下拉选择框选择缓冲区容量、生产者、消费者数量以及速度进行模拟
(进程与界面展示不同步)
在这里插入图片描述
由于作者比较憨批所以界面什么的都堆在一起了 不要介意……而且程序可能有bug 体谅一下 主要是学多线程 界面什么的 就不要太在意啦……

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

操作系统 —— 生产者消费者问题JAVA代码实现 [有比较low的界面] 的相关文章

  • 根据图片URL下载到压缩包

    根据图片URL生成到压缩包 vo类工具类方法枚举类 vo类 span class token keyword package span span class token namespace com span class token punc
  • spring boot中thymeleaf配置说明

    spring boot中thymeleaf配置说明 thymeleaf是一种模板引擎 xff0c 可以查看页面的静态效果 也可以让程序员在服务器查看带数据的动态页面效果 引入依赖 xff0c 在pom xml文件添加以下内容 span cl
  • Ubuntu软件安装Ubuntu Software突然无法启动以及安装残留存在Install Release图标

    文章目录 背景Ubuntu默认的Linux内核无法启动Pycharm加载缓慢问题Ubuntu Software安装的软件无法打开 xff0c 即便是Ubuntu Software也无法打开 结果安装Ubuntu系统之后的残留 背景 之前在U
  • vue使用lottie web插件渲染动画

    1 先安装相应的插件 npm install lottie web save 2 引入插件 我这里是局部引入的 import lottieWeb from 39 lottie web 39 3 使用 xff0c 整体代码如下 xff0c 我
  • Apache 配置禁止IP地址访问,只允许使用域名的方式访问

    配置过程 提前安装好httpd服务器 正常IP地址访问效果 编辑主配置文件 在最后面添加如下信息即可 lt VirtualHost 80 gt DocumentRoot var www html error ServerName 192 1
  • 删掉启动分区进不了系统,复活办法(win10)

    删掉EFI启动分区进不了系统可以这样复活 xff08 win10 xff09 一 复活流程1 u盘制作启动盘2 创建efi分区 二 可能遇到的其他问题 一 复活流程 1 u盘制作启动盘 gt 链接直达 gt gt xff1a win10官方
  • 谈谈你对 多线程 的理解........

    目录 一 认识线程 xff1a xff08 1 xff09 线程和进程的区别 xff1a xff08 面试 xff09 xff08 2 xff09 线程创建 xff1a 二 Thread类及常见方法 xff1a xff08 1 xff09
  • GreenDao和Room

    GreenDao和Room比较 一个小测试insert 增select 查询所有update 修改同位置一条数据delete 删除同位置一条数据写了个kotlin的Room测了下 看如下结果总结 一个小测试 GreenDao版本 imple
  • Datawhale数据分析第一章第一节:数据载入及初步观察

    复习 这门课程得主要目的是通过真实的数据 xff0c 以实战的方式了解数据分析的流程和熟悉数据分析python的基本操作 知道了课程的目的之后 xff0c 我们接下来我们要正式的开始数据分析的实战教学 xff0c 完成kaggle上泰坦尼克
  • VsCode使用相关

    1 解决VsCode控制条使用powershell问题 xff1a set ExecutionPolicy RemoteSigned 2 解决使用yarn安装报版本依赖问题 可升级依赖或忽略 yarn install ignore engi
  • python之Tkinter使用详解

    一 前言 1 1 Tkinter是什么 Tkinter 是使用 python 进行窗口视窗设计的模块 Tkinter模块 Tk 接口 是Python的标准Tk GUI工具包的接口 作为 python 特定的GUI界面 xff0c 是一个图像
  • 实现使用libevent库创建服务器连接多个客户端并实现数据互发

    需要的头文件包含c库 Unix系统库和envent事件库 include lt sys types h gt include lt sys socket h gt include lt netinet in h gt include lt
  • 基于libevent库实现http-sever-restful-API

    文章目录 一 环境搭建 xff1a 1 编译libevent 2 1 11 stable2 cJSON库 二 makefile三 code四 测试测试结果如下 xff1a 一 环境搭建 xff1a 参考 xff1a https blog c
  • vscode通过跳板机连接远程服务器(亲测可用)

    一 windows用户需要先配置好本地的Remote SSH相关服务并开启服务 二 打开VS Code xff0c 在扩展中搜索 34 Remote SSH 34 并安装 三 ctrl 43 shift 43 p呼出控制面板搜索remote
  • 如何抓取log

    一 Catcher log Catcher是 MTK 提供的功能机上一个功能比较强大的一个 log 工具 Catcher log 一般情况下使我们使用起来最多也最方便的一种 xff0c 不用跳线 xff0c 连接上 USB 就行 Catch
  • android studio (record audio)一些问题记录

    2022 03 29 19 23 16 253 1659 1706 E Request requires android permission RECORD AUDIO 2022 03 29 19 23 16 253 1659 1706 E
  • 向量的点乘和叉乘

    向量是由n个实数组成的一个n行1列 xff08 n1 xff09 或一个1行n列 xff08 1n xff09 的有序数组 一 向量的点乘 也叫向量的内积 数量积 xff0c 对两个向量执行点乘运算 xff0c 就是对这两个向量对应位一一相
  • C语言 生产者消费者问题

    目录 生产者消费者问题算法设计实现源程序测试日志总结 生产者消费者问题 算法设计 实现 1 编写所需头文件 span class token macro property span class token directive keyword
  • 操作系统-进程同步:生产者-消费者问题

    文章目录 进程同步 xff1a 生产者 消费者问题问题描述实验环境输入输出测试数据实验设计数据结构系统框架图流程图 实验结果与分析结果展示与描述结果分析总结 源代码 进程同步 xff1a 生产者 消费者问题 问题描述 以生产者 消费者模型为
  • 《动手学习深度学习》预备知识——自动求导

    自动微分 正如我们在 numref sec calculus中所说的那样 xff0c 求导是几乎所有深度学习优化算法的关键步骤 虽然求导的计算很简单 xff0c 只需要一些基本的微积分 但对于复杂的模型 xff0c 手工进行更新是一件很痛苦

随机推荐