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!