This is the 15th day of my participation in the August More text Challenge. For details, see: August More Text Challenge

  • This program simulates the process of solving the producer-consumer problem, and dynamically demonstrates the operation process of P and V, as well as the workflow between the producer-consumer process.
  • The algorithm used in this program is a typical P, V operation using semaphores to solve the “producer-consumer” problem.

This program uses the Java Swing interface function in the interface, with the rectangular bar to represent the producer process to be produced in the product, and set up three partitions respectively to represent the producer process to be produced in the product, the public buffer pool has produced the product and the consumer process has consumed the product, The animation effect shows the process of the product to be produced into the consumer, and the process of the coordination between the producer process and the consumer process.

  • Two producer threads and two consumer threads are used to work concurrently during the program running, and the strategy of random sleep of threads is used, that is, each thread randomly sleeps for 1 to 10 seconds after completing a production or consumption process. This strategy can guarantee the operation order is broken, between producers and consumers to produce the contradiction between production and consumption products (i.e., the absence of consumable products consumers tried to public buffer pool product consumption, public products in the buffer pool is full of producers to produce the product into the buffer pool). Because the producer produces the product and the consumer consumes the product randomly, so the contradiction is also unpredictable, in this case, can test the robustness and efficiency of the algorithm used. This program is designed based on this idea to simulate the process of solving the producer consumer problem.
  • This program at run time to provide friendly interactive interface, and the operation is simple, in the simulation process of various situations have the corresponding text prompt, and accompanied by the corresponding image changes! And embedded help documents!

Program structure:

Run Main

package frame;

import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;

public class CenterPanel extends JPanel{
	
	/ * * *@Fields serialVersionUID : 
	*/ 
	private static final long serialVersionUID = 1L;

	public CenterPanel(a) {
		this.setBackground(Color.WHITE);
	}
	
	@Override
	public void paint(Graphics g) {
		super.paint(g);
		g.setColor(Color.gray);
		// Draw all products in the producer queue (not threads)
		for(int i=0; i<MyFrame.proList.size(); i++) { g.fill3DRect(35, i*20+5.200.20.true);
			g.drawString(MyFrame.proList.get(i), 235, i*20+15);
		}
		
		if(MyFrame.isFull()) {
			// If the public buffer pool is full, turn the buffer in the public buffer pool yellow
			g.setColor(Color.YELLOW);
		}
		// Draw all buffers in the common buffer pool (not threads)
		for(int i=0; i<MyFrame.comList.size(); i++) { g.fill3DRect(285, i*20+5.200.20.true);
			g.drawString(MyFrame.comList.get(i), 485, i*20+15);
		}
		
		// Change the brush color back to gray
		g.setColor(Color.gray);
		// Draw all acquired tasks (not threads) in the consumer queue
		for (int i = 0; i < MyFrame.conList.size(); i++) {
			g.fill3DRect(535, i * 20 + 5.200.20.true);
			g.drawString(MyFrame.conList.get(i), 735, i*20+15);
		}
		
		if(MyFrame.isEmpty()) {
			// If the public buffer pool is empty
			g.setColor(Color.red);
			g.fill3DRect(285.5.200.200.true);
			g.setColor(Color.black);
			g.drawString("Empty".385.100); }}}Copy the code
package frame;

import java.awt.Font;
import java.util.LinkedList;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.border.TitledBorder;

import main.Main;

/ * * *@ClassName: MyFrame
* @Description: Design the interactive interface *@author OuO
* @dateMay 1, 2020 at 9:54:42 am */ 
public class MyFrame extends JFrame{
	/ * * *@Fields serialVersionUID : 
	*/ 
	private static final long serialVersionUID = 1L;
	public static JPanel topPanel, lowPanel, lablePanel;
	public static JTextArea  textArea;
	public static JScrollPane textScroll;
	public static JButton startButton, helpButton;
	public static JComboBox<String> jcb;
	public static CenterPanel centerPanel;
	
	/ * * *@FieldsProList: list of products to be produced by the producer */ 
	/ * * *@FieldsConList: linked list of products that consumers have consumed */ 
	/ * * *@FieldsComList: linked list of common buffer pools */ 
	public  static  LinkedList<String> proList,conList,comList;
	
	/ * * *@FieldsFull: Whether the public buffer pool is full */ 
	public static  boolean full=false;
	
	/ * * *@FieldsEmpty: whether the public buffer pool is empty */ 
	public static boolean empty=false;
	Main m=new Main();
	
	// Initialize the list
	static {
		proList=new LinkedList<>();
		conList=new LinkedList<>();
		comList=new LinkedList<>();
	}

// public Cipher cipher=new Cipher();
	public MyFrame(a) {	
		// Set the text box font
		Font textFont=new Font("宋体", Font.PLAIN, 20);	
		// Set the component layout in the upper-left corner
		topPanel=setTopLeftPanel();	
		// Define the component section in the upper right corner
		textArea = new JTextArea(20.10);
		textArea.setEditable(false);
		textScroll = new JScrollPane();
		textScroll.setViewportView(textArea);
		textScroll.setColumnHeaderView(new JLabel("Text display"));
		textArea.setFont(textFont);	
		// Define the middle (i.e. display box) component
		lablePanel=setLablePanel();
		centerPanel=new CenterPanel();
		// Define the bottom button component
		lowPanel=new JPanel();
		lowPanel.setLayout(null);
		startButton=new JButton("Start");
		// Add listener
		startButton.addActionListener(m);
		helpButton=new JButton("Help");
		helpButton.addActionListener(m);
		startButton.setBounds(210.1.70.35);
		helpButton.setBounds(450.1.70.35);
		lowPanel.add(startButton);
		lowPanel.add(helpButton);		
		// Add all components to the JFrame
		this.setLayout(null);
		topPanel.setBounds(20.10.350.170);
		textScroll.setBounds(400.10.350.170);
		lablePanel.setBounds(0.190.770.25);
		centerPanel.setBounds(0.220.770.350);
		lowPanel.setBounds(20.580.750.40);
		this.add(topPanel);
		this.add(textScroll);
		this.add(lablePanel);
		this.add(centerPanel);
		this.add(lowPanel);
		this.setTitle("Producer-consumer by GodOuO"); setSize(770.680);
		setVisible(true);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setResizable(false);
		setLocation(200.200);
	}
	
	/ * * *@Title: setTopLeftPanel
	* @Description: // Defines the upper-left component section *@returnVoid Return type *@throws* / 
	private JPanel setTopLeftPanel(a) {
		JLabel numberLabel=new JLabel("Maximum number of buffers in a public buffer pool");
		JPanel panel = new JPanel();
		panel.setBorder(BorderFactory.createTitledBorder(null."Choice", TitledBorder.CENTER, TitledBorder.TOP));
		// Reset the layout of topPanel1
		panel.setLayout(null);
		JPanel panel1 = new JPanel();
		panel1.setLayout(null);
		JPanel panel2 = new JPanel();
		panel2.setLayout(null);
		/ / a drop-down box
		String []numberStr= {"1"."2"."10"};
		jcb=new JComboBox<String>(numberStr);
		// Set the position of each component in the panel
		numberLabel.setBounds(70.20.200.20);
		panel1.add(numberLabel);
		jcb.setBounds(70.10.150.20);
		panel2.add(jcb);
		panel1.setBounds(30.15.300.49);
		panel2.setBounds(30.70.300.90);
		panel.add(panel1);
		panel.add(panel2);
		return panel;
	}
	
	/ * * *@Title: setLablePanel
	* @Description: Defines the component * of the graphics display area@return   
	* @returnJPanel return type *@throws* / 
	private JPanel setLablePanel(a) {
		JPanel panel=new JPanel();
		panel.setLayout(null);
		JLabel proLabel,comLabel,conLabel;
		proLabel=new JLabel("Products to be produced");
		comLabel=new JLabel("Public buffer pool (manufactured product)");
		conLabel=new JLabel("Consumed products");		
		// Set the layout
		proLabel.setBounds(35.5.200.20);
		comLabel.setBounds(285.5.200.20);
		conLabel.setBounds(535.5.200.20);		
		panel.add(proLabel);
		panel.add(comLabel);
		panel.add(conLabel);
		return panel;	
	}

	public synchronized static boolean isFull(a) {
		return full;
	}

	public synchronized static void setFull(boolean f) {
		full = f;
	}

	public synchronized static boolean isEmpty(a) {
		return empty;
	}

	public synchronized static void setEmpty(boolean e) { empty = e; }}Copy the code
package main;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.swing.JOptionPane;
import frame.MyFrame;

public class Main implements ActionListener{

	static MyFrame myFrame;
	static ProducerConsumer producerConsumer;
	public static void main(String[] args) {
		myFrame=new MyFrame();
		new ProducerConsumer();
	}
	
	/* (non-Javadoc) * Title: actionPerformed * Description: Listen for an event, click on the button to make corresponding response * @ param e * @ see Java awt. Event. ActionListener# actionPerformed (Java. The awt. Event. An ActionEvent) * / 
	@Override
	public void actionPerformed(ActionEvent e) {
		
		if(e.getSource()==MyFrame.startButton) {
			// Click the Start button
			// Clear the display box
			MyFrame.textArea.setText("");
			util.clear();
			String numbers=(String) MyFrame.jcb.getSelectedItem();
			producerConsumer=new ProducerConsumer();
			producerConsumer.setMAX(Integer.valueOf(numbers));
			producerConsumer.run();
			
		}
		
		if(e.getSource()==MyFrame.helpButton) {
			// Click the button
			File file=new File("./source/help.text");
			try {
				new MyHelp().showHelpWin(file);
			} catch (Exception e1) {
				e1.printStackTrace();
				JOptionPane.showMessageDialog(myFrame, "Cannot open help document, please contact GodOuO"."Help", JOptionPane.PLAIN_MESSAGE); }}}}Copy the code
package main;

import java.io.BufferedReader;
import java.io.File;
import java.io.InputStream;
import java.io.InputStreamReader;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

/ * * *@ClassName: MyHelp
* @Description: Help window *@author OuO
* @dateMay 1, 2020, 10:15:50 a.m. */ 
public class MyHelp extends JFrame{

	/ * * *@Fields serialVersionUID : 
	*/ 
	private static final long serialVersionUID = 1L;
	JTextArea textArea = null;
	JScrollPane jsp = null;
	
	/ * * *@Title: showHelpWin
	* @Description: The help window pops up when you click the Help button@paramFile Help document *@throws Exception   
	* @returnVoid Return type *@throws* / 
	public void showHelpWin(File file) throws Exception {
		this.setVisible(true);
		this.setSize(580.300);
		this.setLocation(300.250);
		textArea = new JTextArea();
		jsp = new JScrollPane(textArea);
		textArea.setText(null);
		textArea.setEditable(false);
		// Read the file
		InputStream is=MyHelp.class.getClassLoader().getResourceAsStream("help.txt");
		InputStreamReader isr = new InputStreamReader(is, "UTF-8");
		BufferedReader buf = new BufferedReader(isr);
		
		String str = null;
		while((str = buf.readLine()) ! =null) {
			textArea.append(str);
			textArea.append("\r\n"); } add(jsp); buf.close(); }}Copy the code
package main;

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

import frame.MyFrame;

public class ProducerConsumer extends Thread{
    
    / * * *@FieldsMAX: specifies the maximum number of buffers */ 
    private int MAX = 1;
    
    / * * *@FieldsLock: A lock object that locks and releases */ for critical sections 
    private final Lock lock = new ReentrantLock();
    
    / * * *@FieldsFull: the buffer pool is full */ 
    private final Condition full = lock.newCondition();
    
    / * * *@FieldsEmpty: empty buffer */ in the buffer 
    private final Condition empty = lock.newCondition();
    
    / * * *@FieldsNumbers: Number of products to be produced in the producer queue */ 
    private int numbers=100;

    public ProducerConsumer(a) {
        for(int i=0; i<numbers; i++) { MyFrame.proList.add(newString(String.valueOf(i))); }}@Override
    public void run(a) {
    	new Producer().start();
        new Consumer().start();
        new Producer().start();
        new Consumer().start();
    }
   
    public synchronized int getNumbers(a) {
		return numbers;
	}

	
	public synchronized int getMAX(a) {
		return MAX;
	}

	public synchronized void setMAX(int mAX) {
		MAX = mAX;
	}

	
	public synchronized void lessNumber(a) {
		this.numbers=this.numbers-1;
	}

	/ * * *@ClassName: Producer
    * @Description: Producer process *@author OuO
    * @dateMay 1, 2020 2:15:39 PM */ 
    class Producer extends Thread {
		
    	/* (non-javadoc) * Title: run * Description: Override the run method * @see java.lang.thread #run() */ 
    	@Override
        public void run(a) {
            while (getNumbers()>=1) {
            	/ / lock
                lock.lock();
                try {
                	// The thread stops for 3 seconds to make the program run more slowly
                	sleep(3000);
                   if (MyFrame.comList.size() == getMAX()) {
                	   // If the public buffer pool is full, add the current process to the wait queue
                	   // Until awakened: full. Signal
                        util.showInfo("Warning: Full! \n Producer blocked \n");
                        MyFrame.setFull(true);
                        // Refresh the screen
                        MyFrame.centerPanel.repaint();
                        // The current process enters the waiting queue
                        full.await();
                    }
                   
                    String str = MyFrame.proList.removeLast();
                    if (MyFrame.comList.add(str)) {
                    	// If the object is successfully added to the comList queue
                    	// Indicate that the producer process successfully produced a product and fed it into the common buffer pool
                    	util.showInfo("Producer:"+str+"\n");
                    	MyFrame.setEmpty(false);
                        MyFrame.centerPanel.repaint();
                        // Wake up the waiting consumer processempty.signal(); }}catch (InterruptedException ie) {
                	// An exception is caught indicating that the process is abnormally interrupted
                	util.showInfo("Abnormal production terminated! \n");
                } finally {
                	// Reduce the number by one
                	lessNumber();
                	/ / releases the lock
                    lock.unlock();
                    try {
                    	The thread is paused randomly for a few seconds in order to cause conflicts between the producer and the consumer
                    	// To achieve the purpose of demonstration
						sleep(new Random().nextInt(10000));
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
                }
            }
        }
    }

    / * * *@ClassName: Consumer
    * @Description: Consumer process *@author OuO
    * @dateMay 1, 2020 2:35:56 PM */ 
    class Consumer extends Thread {
    	
    	/* (non-javadoc) * Title: run * Description: Override the run method * @see java.lang.thread #run() */ 
    	@Override
        public void run(a) {
            while(! (getNumbers()==0 && MyFrame.comList.size()==0)) {
            	/ / lock
                lock.lock();
                try {
                	// The thread stops for 2 seconds to make the program run more slowly
                	sleep(2000);
                    if (MyFrame.comList.size() == 0) {
                    	// If comList length is 0, no buffer is available in the public buffer pool
                    	// That is, the buffer is empty and no product is available
                    	util.showInfo("Warning: Empty! \n Consumers blocked! \n");
                    	MyFrame.setEmpty(true);
                    	// Refresh the screen
                    	MyFrame.centerPanel.repaint();
                    	
                        // Put the current process on the wait queue until it is awakened: empty.signal()
                        empty.await();
                    }
                    
                	// The consumer process successfully pulled the product from the buffer pool
                    String str = MyFrame.comList.removeLast();
                    if(MyFrame.conList.add(str)) {
                    	util.showInfo("Consumer:" + str+"\n");
                    	MyFrame.setFull(false);
                    	 MyFrame.centerPanel.repaint();
                         // Wake up the waiting producer processfull.signal(); }}catch (InterruptedException ie) {
                	util.showInfo("An abnormal end to consumption! \n");
                } finally {
                	/ / releases the lock
                    lock.unlock();
                    try {
                    	The thread is paused randomly for a few seconds in order to cause conflicts between the producer and the consumer
                    	// To achieve the purpose of demonstration
						sleep(new Random().nextInt(8000));
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
                }
            }
            util.showInfo("The end"); }}}Copy the code
package main;

import frame.MyFrame;

public class util {
	/ * * *@Title: showInfo
	* @Description: Adds a string to the display box to display *@param string   
	* @returnVoid Return type *@throws* / 
	public synchronized static void showInfo(String string) {
		// Add the string to the display box
		MyFrame.textArea.append(string);
		// The display box scroll bar automatically follows the last line of text
		MyFrame.textArea.setCaretPosition(MyFrame.textArea.getDocument().getLength());
	}

public static void clear(a) {
		MyFrame.proList.clear();
		MyFrame.comList.clear();
		MyFrame.conList.clear();
		MyFrame.setEmpty(false);
		MyFrame.setFull(false); }}Copy the code

Ps: help.txt can be written into the program!