队列模型(M/M/1)仿真程序实现
编程实现队列模型(M/M/1)的仿真程序
输入参数:平均到达时间,平均服务时间,顾客数目,队列最大长度;
输出参数:队列中平均等待客户数;平均等待时间;服务器利用率。
(使用下一事件时间推进法仿真时间推进)
代码实现
Main.java
/* ----------
created by hswyx666
2020/10/28
---------- */
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JButton;
import java.awt.Color;
import java.awt.Font;
import java.util.Arrays;
import java.util.LinkedList;
public class Main {
private JFrame frame = new JFrame("M/M/1 队列模型");
private JLabel inputLabel = new JLabel("输入");
private JLabel[] paramLabel = new JLabel[4];
private JLabel outputLabel = new JLabel("输出");
private JLabel[] resultsLabel = new JLabel[3];
private JButton executeButton = new JButton("计算");
private MyTextField[] inputTextField = new MyTextField[4];
private MyTextField[] outputTextField = new MyTextField[3];
private JLabel illegalLabel = new JLabel("输入数据不合法!");
private JLabel explanationLabel = new JLabel("注:正在服务的顾客不算在队列内");
private double averageArriveTime;
private double averageServeTime;
private int customerNum;
private int maxQueueLen;
private double[] arriveTimes;
private double[] serveTimes;
private double averageWaitNum; //平均等待数目
private double averageWaitTime; //平均等待时间
private double utilizeRate; //利用率
private void setLayOut() {
frame.setResizable(true);
frame.setLayout(null);
frame.setBounds(10, 10, 900, 600);
frame.setLocation(500, 250);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setBackground(new Color(0x66ccff)); //锦依卫色!!!
inputLabel.setFont(new Font("宋体", Font.BOLD, 30));
inputLabel.setForeground(Color.BLACK);
inputLabel.setBounds(240, 40, 150, 40);
frame.add(inputLabel);
outputLabel.setFont(new Font("宋体", Font.BOLD, 30));
outputLabel.setForeground(Color.BLACK);
outputLabel.setBounds(550, 40, 150, 40);
frame.add(outputLabel);
String[] paramTexts = {"平均到达时间", "平均服务时间", "顾客数目", "队列最大长度"};
for (int i = 0; i < 4; i++) {
paramLabel[i] = new JLabel(paramTexts[i]);
paramLabel[i].setFont(new Font("仿宋", Font.BOLD, 18));
paramLabel[i].setBounds(80, 100 + i * 100, 150, 40);
frame.add(paramLabel[i]);
inputTextField[i] = new MyTextField();
inputTextField[i].setBounds(200, 100 + i * 100, 150, 40);
frame.add(inputTextField[i]);
}
String[] resultsTexts = {"平均等待客户数", "平均等待时间", "服务器利用率"};
for (int i = 0; i < 3; i++) {
resultsLabel[i] = new JLabel(resultsTexts[i]);
resultsLabel[i].setFont(new Font("仿宋", Font.BOLD, 18));
resultsLabel[i].setBounds(675, 100 + i * 150, 150, 40);
frame.add(resultsLabel[i]);
outputTextField[i] = new MyTextField();
outputTextField[i].setBounds(500, 100 + 150 * i, 150, 40);
frame.add(outputTextField[i]);
}
executeButton.setFont(new Font("宋体", Font.BOLD, 30));
executeButton.setBounds(360, 475, 150, 50);
executeButton.addMouseListener(new MyMouseListener(this));
frame.add(executeButton);
illegalLabel.setFont(new Font("等线", Font.BOLD, 15));
illegalLabel.setBounds(375, 430, 150, 50);
illegalLabel.setVisible(false);
frame.add(illegalLabel);
explanationLabel.setFont(new Font("等线", Font.BOLD, 15));
explanationLabel.setBounds(600, 500, 250, 50);
frame.add(explanationLabel);
frame.setVisible(true);
}
void inputData() throws NumberFormatException {
illegalLabel.setVisible(false);
try {
averageArriveTime = inputTextField[0].getDouble();
averageServeTime = inputTextField[1].getDouble();
customerNum = inputTextField[2].getInt();
maxQueueLen = inputTextField[3].getInt();
} catch (NumberFormatException e) {
displayIllegalInformation();
}
if (customerNum <= 0 || maxQueueLen < 0) {
throw new NumberFormatException();
}
}
void calculate() {
arriveTimes = new double[customerNum];
serveTimes = new double[customerNum];
arriveTimes[0] = -averageArriveTime * Math.log(1 - Math.random());
for (int i = 1; i < customerNum; i++) {
double r1 = Math.random();
arriveTimes[i] = arriveTimes[i - 1] - averageArriveTime * Math.log(1 - r1); //指数分布
}
double firstArriveTime = arriveTimes[0];
for (int i = 0; i < customerNum; i++) {
arriveTimes[i] -= firstArriveTime;
}
for (int i = 0; i < customerNum; i++) {
double r2 = Math.random();
double randomArriveTime = -averageServeTime * Math.log(1 - r2); //指数分布
serveTimes[i] = randomArriveTime;
}
double lastLeaveTime = 0; //上一位顾客离开时间
int newCustomerNum = clearIllegalCustomer();
double[] leaveTimes = new double[newCustomerNum];
double[] waitTimes = new double[newCustomerNum]; //等待时间
for (int i = 0; i < newCustomerNum; i++) {
if (arriveTimes[i] < lastLeaveTime) {
leaveTimes[i] = serveTimes[i] + lastLeaveTime;
waitTimes[i] = lastLeaveTime - arriveTimes[i];
}
else {
leaveTimes[i] = arriveTimes[i] + serveTimes[i];
waitTimes[i] = 0;
}
lastLeaveTime = leaveTimes[i];
}
double workTimeSum = 0;
for (double serveTime: serveTimes) {
workTimeSum += serveTime;
}
utilizeRate = workTimeSum / (leaveTimes[newCustomerNum - 1] + firstArriveTime);
double waitTimeSum = 0;
for (double waitTime: waitTimes) {
waitTimeSum += waitTime;
}
averageWaitNum = waitTimeSum / (leaveTimes[newCustomerNum - 1] + firstArriveTime);
averageWaitTime = waitTimeSum / (double)newCustomerNum;
}
private int clearIllegalCustomer() { //去掉因等待队列过长离开的顾客
double lastLeaveTime = 0;
LinkedList<Double> legalArriveTimes = new LinkedList<>();
LinkedList<Double> legalServeTimes = new LinkedList<>();
for (int i = 0; i < customerNum; i++) {
legalArriveTimes.add(arriveTimes[i]);
legalServeTimes.add(serveTimes[i]);
}
for (int i = 0; i < legalArriveTimes.size(); i++) {
if (legalArriveTimes.get(i) < lastLeaveTime) {
lastLeaveTime += legalArriveTimes.get(i);
}
else {
lastLeaveTime = legalArriveTimes.get(i) + legalServeTimes.get(i);
}
int j;
for (j = i + 1; j < legalArriveTimes.size(); j++) {
if (legalArriveTimes.get(j) > lastLeaveTime) {
break;
}
}
for (j--; j > i; j--) { //一定要反向删除
if (j - i > maxQueueLen) {
legalArriveTimes.remove(j);
legalServeTimes.remove(j);
}
}
}
arriveTimes = new double[legalArriveTimes.size()];
serveTimes = new double[legalServeTimes.size()];
for (int i = 0; i < legalArriveTimes.size(); i++) {
arriveTimes[i] = legalArriveTimes.get(i);
serveTimes[i] = legalServeTimes.get(i);
}
return legalArriveTimes.size();
}
void outputData() {
outputTextField[0].setText(String.format("%.3f", averageWaitNum));
outputTextField[1].setText(String.format("%.3f", averageWaitTime));
outputTextField[2].setText(String.format("%.2f%%", utilizeRate * 100));
}
void displayIllegalInformation() {
illegalLabel.setVisible(true);
}
public static void main(String[] args) {
Main main = new Main();
main.setLayOut();
}
}
MyMouseListener.java
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class MyMouseListener implements MouseListener {
private Main main;
MyMouseListener(Main main) {
this.main = main;
}
@Override
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1) {
try {
main.inputData();
main.calculate();
main.outputData();
} catch (NumberFormatException ex) {
main.displayIllegalInformation();
}
}
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
}
@Override
public void mouseEntered(MouseEvent e) {
}
@Override
public void mouseExited(MouseEvent e) {
}
}
MyTextField.java
import javax.swing.JTextField;
import java.awt.Font;
class MyTextField extends JTextField {
MyTextField() {
super();
setFont(new Font("楷体", Font.BOLD, 20));
setHorizontalAlignment(LEFT);
}
double getDouble() throws NumberFormatException {
return new Double(getText());
}
int getInt() throws NumberFormatException {
return new Integer(getText());
}
}