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

生产者消费者问题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 体谅一下 主要是学多线程 界面什么的 就不要太在意啦……

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Arik (IoT)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值