javaGUI——生产者消费者问题

本程序原作链接:https://blog.csdn.net/GodOuO/article/details/105879961
(拜谢)
本程序基于原文程序完成,原程序会出现缓冲池限制不起作用,导致生产者一直放的问题,所以对程序进行了重构,加了一个显示生产者消费者状态的界面。
直接按照这个结构复制文中的代码可以直接运行。

  • 程序文件结构

在这里插入图片描述

  • 运行截图

在这里插入图片描述

  • 源码

MyFrame

package myframe;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.LinkedList;
import javax.swing.*;
import javax.swing.border.TitledBorder;

import thread.P_C;

public class MyFrame extends JFrame{
	private static final long serialVersionUID = 1222538739701278727L;
	//主界面的各个画板
	@SuppressWarnings("unused")
	private  JPanel toprightpanel,topleftpanel,midpanel,buttonpanel;
	//中间显示区画板
	public static MyShowPanel showpanel;
	private  JButton beginbutton;
	private static  JTextArea textcout;
	private  JScrollPane scrollpane;
	//选择下拉框
	private  JComboBox<String> catch_choice;
	private  JComboBox<String> pro_choice;
	private JComboBox<String> con_choice;
	//生产,消费,缓冲队列
	public static  LinkedList<String> pro_list;
	public static LinkedList<String> con_list;
	public static LinkedList<String> catch_list;
	//缓冲池大小,生产者数量,消费者数量
	public static int catch_num,pro_num,con_num;
	//缓冲池状态
	private static  boolean empty;
	private static boolean full;
	//子窗口显示生产者消费者状态
	private static JFrame subFrame;
	//显示生产者消费者的画板
	public static sumpanel subPanel;
	//生产者消费者的状态数组
	public static boolean[] prostate;
	public static boolean[] constate;
	
	/**
	 * @return
	 * empty getter
	 */
	public static boolean isempty() {
		return empty;
	}
	/**
	 * @param is
	 * empty setter
	 */
	public static void setempty(boolean is) {
		empty=is;
	}
	/**
	 * @return
	 * full getter
	 */
	public static boolean isfull() {
		return full;
	}
	/**
	 * @param is
	 * full setter
	 */
	public static void setfull(boolean is) {
		full=is;
	}

	/**
	 * 清空界面和状态
	 */
	public void clear() {
		pro_list.clear();
		catch_list.clear();
		con_list.clear();
		setempty(false);
		setfull(false);
	}
	//字体
	private static Font font=new Font("宋体", Font.PLAIN, 20);
	//静态初始化
	static {
		empty=false;
		full=false;
		pro_num=100;
		pro_list=new LinkedList<>();
		con_list=new LinkedList<>();
		catch_list=new LinkedList<>();
	}
	MyFrame(){
		this.setFont(font);
		//初始化各组件信息
		topleftpanel();
		scrollpane.setBounds(20, 10, 350, 170);
		
		toprightpanel();
		toprightpanel.setBounds(400, 10, 350, 170);
		
		midlabel();
		midpanel.setBounds(20, 190, 800, 20);
		
		lowpanel();
		buttonpanel.setBounds(20,580,750,40);
		
		showpanel=new MyShowPanel();
		showpanel.setBounds(0,220,770,350);
		
		subFrame=new JFrame();
		//添加组件
		this.setLayout(null);
		this.add(toprightpanel);
		this.add(scrollpane);
		this.add(midpanel);
		this.add(buttonpanel);
		this.add(showpanel);
		
		//设置窗口属性
		setSize(770, 680);
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setResizable(false);//窗口大小不可变
		setLocation(200,200);
	}
	/**
	 * @param string
	 * 输出文字信息
	 */
	public static void showInfo(String string) {
		textcout.append(string);
		//自动跟随文字
		textcout.setCaretPosition(textcout.getDocument().getLength());
	}
	/**
	 * 创建顶部右侧选择画板
	 */
	private void toprightpanel() {
		JLabel toprightprolabel,toprightcatchlabel,toprightconlabel;
		String []numberStr= {"0","1","2","3","4","5","6","7","8","9","10"};
		
		toprightprolabel=new JLabel();
		toprightprolabel.setText("生产者数量");
		toprightprolabel.setBounds(5,5,80,20);
		pro_choice=new JComboBox<String>(numberStr);
		pro_choice.setBounds(90,5,60,20);
		JPanel pane1=new JPanel();
		pane1.setLayout(null);
		pane1.add(toprightprolabel);
		pane1.add(pro_choice);
		
		toprightconlabel=new JLabel();
		toprightconlabel.setText("消费者数量");
		toprightconlabel.setBounds(5, 5,80, 20);
		con_choice=new JComboBox<String>(numberStr);
		con_choice.setBounds(90,5,60,20);
		JPanel pane2=new JPanel();
		pane2.setLayout(null);
		pane2.add(toprightconlabel);
		pane2.add(con_choice);
		
		toprightcatchlabel=new JLabel();
		toprightcatchlabel.setText("缓冲池大小");
		toprightcatchlabel.setBounds(5, 5,80, 20);
		catch_choice=new JComboBox<String>(numberStr);
		catch_choice.setBounds(90,5,60,20);
		JPanel pane3=new JPanel();
		pane3.setLayout(null);
		pane3.add(toprightcatchlabel);
		pane3.add(catch_choice);
		
		
		toprightpanel=new JPanel();
		toprightpanel.setBorder(BorderFactory.createTitledBorder(null, "选择", TitledBorder.LEFT, TitledBorder.TOP));
		toprightpanel.setLayout(new BoxLayout(toprightpanel,BoxLayout.Y_AXIS));
		toprightpanel.add(pane1);
		toprightpanel.add(pane2);
		toprightpanel.add(pane3);
	}
	/**
	 * 创建顶部左侧画板
	 */
	private void topleftpanel() {
		textcout=new JTextArea(20,10);
		textcout.setEditable(false);
		scrollpane=new JScrollPane();
		scrollpane.setViewportView(textcout);
		scrollpane.setColumnHeaderView(new JLabel("文字显示"));
		textcout.setFont(font);	
			
	}
	/**
	 * 中间label
	 */
	private void midlabel() {
		JLabel prolabel,catchlabel,conlabel;
		prolabel=new JLabel();
		conlabel=new JLabel();
		catchlabel=new JLabel();
		
		prolabel.setText("生产者");
		conlabel.setText("消费者");
		catchlabel.setText("缓冲池");
		
		prolabel.setBounds(35,5,200,20);
		conlabel.setBounds(535,5,200,20);
		catchlabel.setBounds(285,5,200,20);
		
		midpanel=new JPanel();
		midpanel.setLayout(null);
		midpanel.add(prolabel);
		midpanel.add(conlabel);
		midpanel.add(catchlabel);
	}
	/**
	 * 底部按钮
	 */
	private void lowpanel() {
		beginbutton=new JButton();
		beginbutton.setText("开始");
		beginbutton.setBounds(310,1,70,35);
		beginbutton.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) {
				if(e.getSource()==beginbutton) {
					//子窗口
					pro_num=Integer.valueOf((String)pro_choice.getSelectedItem());
					catch_num=Integer.valueOf((String)catch_choice.getSelectedItem());
					con_num=Integer.valueOf((String)con_choice.getSelectedItem());
					prostate=new boolean[pro_num];
					constate=new boolean[con_num];
					setstate();
					
					subPanel=new sumpanel(pro_num,con_num);
					subFrame.setLayout(null);
					subPanel.setBounds(5, 5, 305, 305);
					subFrame.setSize(400,400);
					subFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
					subFrame.add(subPanel);
					subFrame.setLocation(200,200);
					subFrame.setVisible(true);
					clear();
					textcout.setText("");
					P_C pc=new P_C();
					
					pc.setThreadnum(pro_num, con_num,catch_num);
					pc.run();
				}
				
			}
			
		});
		buttonpanel=new JPanel();
		buttonpanel.setLayout(null);
		buttonpanel.add(beginbutton);
	}
	public static void main(String[]args) {
		@SuppressWarnings("unused")
		MyFrame a=new MyFrame();
	}
	/**
	 * 初始化消费者生产者状态
	 */
	public void setstate() {
		for(int i=0;i<pro_num;i++) {
			prostate[i]=false;
		}
		for(int i=0;i<con_num;i++) {
			constate[i]=false;
		}
	}
	public class MyShowPanel extends JPanel{
		/**
		 * 
		 */
		private static final long serialVersionUID = 4590517425748077768L;
		MyShowPanel(){
			this.setBackground(Color.WHITE);
		}
		@Override
		public void paint(Graphics g) {
			super.paint(g);
			g.setColor(Color.blue);
			for(int i=0;i<pro_list.size();i++) {
				g.fill3DRect(35, i*20+5, 200, 20, true);
				g.drawString(pro_list.get(i), 20, i*20+15);
			}
			if(isfull()) {
				//若公共缓冲池已满,将公共缓冲池里的缓冲区变为红色
				g.setColor(Color.RED);
			}
			g.setColor(Color.gray);
			for(int i=0;i<catch_list.size();i++) {
				g.fill3DRect(285, i*20+5, 200, 20, true);
				g.drawString(catch_list.get(i), 270, i*20+15);
			}
			
			g.setColor(Color.yellow);
			for(int i=0;i<con_list.size();i++) {
				g.fill3DRect(535, i*20+5, 200, 20, true);
				g.drawString(con_list.get(i), 520, i*20+15);
			}
			if(isempty()) {
				//若公共缓冲池为空
				g.setColor(Color.black);
				g.fill3DRect(285, 5, 200, 200, true);
				g.setColor(Color.black);
				g.drawString("空", 385, 100);
			}	
		}
		
	}
	@SuppressWarnings("serial")
	public class sumpanel extends JPanel{
		private int pro_num,con_num;//pro_num是生产者数量,con_num是消费者数量
		sumpanel(int pro,int con){
			setLayout(null);
			pro_num=pro;
			con_num=con;
			//子窗口消费者生产者label数组
			JLabel[] prolabel=new JLabel[pro];
			JLabel[] conlabel=new JLabel[con];
			for(int i=0;i<pro;i++) {
				prolabel[i]=new JLabel();
				prolabel[i].setText((i+1)+"号生产者");
				prolabel[i].setBounds(5, 5+20*i, 100,20 );
				add(prolabel[i]);
			}
			for(int j=0;j<con;j++) {
				conlabel[j]=new JLabel();
				conlabel[j].setText((j+1)+"号消费者");
				conlabel[j].setBounds(180, 5+20*j, 100, 20);
				add(conlabel[j]);
			}
		}
		@Override
		public void paint(Graphics g) {
			super.paint(g);
			g.setColor(Color.green);
			for(int i=0;i<pro_num;i++) {
				if(prostate[i]==true) {
					g.fill3DRect(110,5+20*i,10,10,true);
				}
			}
			g.setColor(Color.green);
			for(int i=0;i<con_num;i++) {
				if(constate[i]) {
					g.fillOval(285, 5+20*i, 10, 10);
				}
			
			}
		}
	}
}

producer

package thread;

import java.util.Random;

import myframe.MyFrame;

public class producer extends Thread{
	private String name;
	producer(){
		this.name=String.valueOf(P_C.namepro++);
	}
	@Override
	public void run() {
		while(P_C.getproduceive()>0) {
			P_C.lock.lock();
			try {
			sleep(3000);
			//缓冲池满则阻塞
			while(MyFrame.catch_list.size()==P_C.catchMAX) {
					//输出线程文字信息
					MyFrame.showInfo("警告:Full! "+name+"号生产者受阻,被阻塞!\n");
					MyFrame.setfull(true);
					//生产者被阻塞,更新其状态
					MyFrame.prostate[Integer.parseInt(name)-1]=false;
					//更新后调用repaint()刷新画面
					MyFrame.subPanel.repaint();
					MyFrame.showpanel.repaint();
					P_C.full.await();
					//生产者被唤醒,更新状态
					MyFrame.prostate[Integer.parseInt(name)-1]=true;
					//调用repaint()刷新画面
					MyFrame.subPanel.repaint();
					//输出线程文字信息
					MyFrame.showInfo(this.name+"号生产者开始\n");
			}
			//开始生产
			MyFrame.prostate[Integer.parseInt(name)-1]=true;
			MyFrame.subPanel.repaint();
			//从生产队列中取走
			String str=MyFrame.pro_list.removeLast();
			if(MyFrame.catch_list.add(str)) {
				MyFrame.showInfo(name+"号生产者生产: "+str+"\n");
				MyFrame.setempty(false);
				MyFrame.showpanel.repaint();
				P_C.empty.signal();
			}else {
				P_C.full.await();
			}
			}catch (InterruptedException ie) {
            	//捕获到异常说明进程被异常中断
            	MyFrame.showInfo("生产异常终止!\n");
            } finally{
            	P_C.lock.unlock();
            	//减少可生产的数量
            	P_C.lessproduceive();
            	try {
                	//线程随机暂停几秒
					sleep(new Random().nextInt(5000));
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
            }
		}
		MyFrame.showInfo("结束");
	}
	
}

consumer

package thread;

import java.util.Random;

import myframe.MyFrame;

public class consumer extends Thread{
	private String name;
	consumer(){
		this.name=String.valueOf(P_C.namecon++);
	}
	@Override
	public void run() {
		while(!(P_C.getproduceive()==0 && MyFrame.catch_list.size()==0)) {
			P_C.lock.lock();
			try {
				sleep(2000);
				//缓冲池空则阻塞
				while(MyFrame.catch_list.isEmpty()) {
					MyFrame.showInfo("警告: Empty!\n"+name+"号消费者受阻!\n");
	            	MyFrame.setempty(true);
	            	//更新消费者状态为false(阻塞)
	            	MyFrame.constate[Integer.parseInt(name)-1]=false;
	            	//刷新画面
	            	MyFrame.showpanel.repaint();
	            	MyFrame.subPanel.repaint();
	            	P_C.empty.await();
	            	//更新消费者状态
	            	MyFrame.constate[Integer.parseInt(name)-1]=true;
	            	//刷新画面
	            	MyFrame.subPanel.repaint();
	            	//输出线程文字信息
	            	MyFrame.showInfo(name+"号消费者开始\n");
				}
				//开始消费
				MyFrame.constate[Integer.parseInt(name)-1]=true;
            	MyFrame.subPanel.repaint();
            	//从缓冲池中取走
				String str=MyFrame.catch_list.removeLast();
				if(MyFrame.con_list.add(str)) {
					MyFrame.showInfo(name+"号消费者取走: " + str+"\n");
	            	MyFrame.setfull(false);
	            	 MyFrame.showpanel.repaint();
	            	 P_C.full.signal();
				}
			}catch (InterruptedException ie) {
	        	MyFrame.showInfo("消费异常终止!\n");
	        }finally {
	        	P_C.lock.unlock();
	        	try {
	            	//线程随机暂停几秒
					sleep(new Random().nextInt(3000));
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
	        }
		}
		
	}
}

P_C

package thread;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import myframe.MyFrame;

public class P_C {
	 public static Lock lock = new ReentrantLock();
	 public static Condition full = lock.newCondition();
	 public static Condition empty = lock.newCondition();
	 //生产者消费者线程数量
	 public static int pro_threadnum,con_threadnum;
	 public static int productive=100;//产品数量
	 //缓冲池大小
	 public static int catchMAX;
	 //生产者名字计数
	 public static int namepro=1;
	 //消费者名字计数
	 public static int namecon=1;
	 /**
	 * @return
	 * productive getter
	 */
	public static int getproduceive() {
		 return productive;
	 }
	 /**
	 * 减少可生产数量
	 */
	public static void lessproduceive() {
		productive--;
	 }
	 public P_C() {
		 MyFrame.pro_list.clear();
		 //初始化生产队列
	        for(int i=0;i<productive;i++) {
	        	MyFrame.pro_list.add(new String(String.valueOf(i)));
	        }
	    }
	 /**
	 * @param pro
	 * @param con
	 * @param catchmax
	 * 设置生产者,消费者,缓冲池大小
	 */
	public void setThreadnum(int pro,int con,int catchmax) {
		 pro_threadnum=pro;
		 con_threadnum=con;
		 catchMAX=catchmax;
	 }
	 /**
	 * 根据生产者,消费者线程数量创建线程
	 */
	public void run() {
		 int max,min,decive;
	    	if(pro_threadnum>=con_threadnum) {
	    		max=pro_threadnum;
	    		min=con_threadnum;
	    		decive=max-min;
	    		for(int i=0;i<min;i++) {
	    			new producer().start();
	    			new consumer().start();
	    		}
	    		for(int i=0;i<decive;i++) {
	    			new producer().start();
	    		}
	    	}
	    	else {
	    		min=pro_threadnum;
	    		max=con_threadnum;
	    		decive=max-min;
	    		for(int i=0;i<min;i++) {
	    			new producer().start();
	    			new consumer().start();
	    		}
	    		for(int i=0;i<decive;i++) {
	    			new consumer().start();
	    		}
	    	}
	    	namepro=1;
	    	namecon=1;
	 }
}

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个基于Java的生产者消费者问题的代码实现,附带GUI界面: ```java import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.List; public class ProducerConsumer extends JFrame implements ActionListener { private final int BUFFER_SIZE = 5; // 缓冲区大小 private final List<Integer> buffer = new ArrayList<>(BUFFER_SIZE); // 缓冲区 private final Object lock = new Object(); // 同步锁对象 private final JLabel bufferLabel = new JLabel(); // 显示缓冲区的标签 private final JTextField producerTextField = new JTextField(8); // 生产者输入框 private final JTextField consumerTextField = new JTextField(8); // 消费者输入框 private final JButton startButton = new JButton("开始"); // 开始按钮 private final JButton stopButton = new JButton("停止"); // 停止按钮 private Producer producer; private Consumer consumer; public ProducerConsumer() { setTitle("生产者消费者问题"); setSize(400, 200); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JPanel panel = new JPanel(); panel.setLayout(new GridLayout(3, 2, 20, 10)); panel.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); panel.add(new JLabel("缓冲区:")); panel.add(bufferLabel); panel.add(new JLabel("生产者:")); panel.add(producerTextField); panel.add(new JLabel("消费者:")); panel.add(consumerTextField); startButton.addActionListener(this); stopButton.addActionListener(this); stopButton.setEnabled(false); panel.add(startButton); panel.add(stopButton); setContentPane(panel); setVisible(true); } @Override public void actionPerformed(ActionEvent e) { if (e.getSource() == startButton) { // 点击开始按钮时,启动生产者消费者线程 producer = new Producer(); consumer = new Consumer(); producer.start(); consumer.start(); startButton.setEnabled(false); stopButton.setEnabled(true); } else if (e.getSource() == stopButton) { // 点击停止按钮时,停止生产者消费者线程 producer.stopThread(); consumer.stopThread(); startButton.setEnabled(true); stopButton.setEnabled(false); } } private void updateBufferLabel() { // 更新缓冲区标签的显示 String bufferText = ""; for (Integer item : buffer) { bufferText += item + " "; } bufferLabel.setText(bufferText); } private class Producer extends Thread { private boolean stop = false; public void stopThread() { stop = true; } @Override public void run() { while (!stop) { synchronized (lock) { // 如果缓冲区已满,则等待 while (buffer.size() == BUFFER_SIZE) { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 生产一个随机数,并添加到缓冲区 int item = (int) (Math.random() * 100); buffer.add(item); System.out.println("生产者生产了:" + item); updateBufferLabel(); // 唤醒一个等待的线程(可能是消费者) lock.notify(); } try { // 线程休眠一段时间,模拟生产过程 Thread.sleep((int) (Math.random() * 2000)); } catch (InterruptedException e) { e.printStackTrace(); } } } } private class Consumer extends Thread { private boolean stop = false; public void stopThread() { stop = true; } @Override public void run() { while (!stop) { synchronized (lock) { // 如果缓冲区为空,则等待 while (buffer.size() == 0) { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 从缓冲区中取出一个元素,并消费它 int item = buffer.remove(buffer.size() - 1); System.out.println("消费者消费了:" + item); updateBufferLabel(); // 唤醒一个等待的线程(可能是生产者) lock.notify(); } try { // 线程休眠一段时间,模拟消费过程 Thread.sleep((int) (Math.random() * 2000)); } catch (InterruptedException e) { e.printStackTrace(); } } } } public static void main(String[] args) { new ProducerConsumer(); } } ``` 运行该程序,将会显示一个GUI界面,包括一个显示缓冲区的标签、两个输入框(分别用于生产者消费者输入数据)、一个开始按钮和一个停止按钮。点击开始按钮,程序将启动一个生产者线程和一个消费者线程,并开始模拟生产者消费者在缓冲区中的操作;点击停止按钮,程序将停止生产者消费者线程,结束模拟过程。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值