本文目录导读:

我为您提供一个完整的Java多线程仿真案例——银行排队系统仿真,包含详细代码和设计说明。
银行排队系统仿真
系统设计
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.*;
/**
* 银行排队系统仿真
* 模拟银行柜台服务、客户到达、排队等待等场景
*/
public class BankSimulation {
// 仿真参数
private static final int NUM_COUNTERS = 5; // 柜台数量
private static final int SIMULATION_MINUTES = 30; // 仿真时长(分钟)
private static final int MAX_ARRIVE_INTERVAL = 3000; // 最大到达间隔(毫秒)
private static final int MIN_ARRIVE_INTERVAL = 500; // 最小到达间隔(毫秒)
private static final int MAX_SERVICE_TIME = 5000; // 最大服务时间(毫秒)
private static final int MIN_SERVICE_TIME = 1000; // 最小服务时间(毫秒)
// 统计数据
private static AtomicInteger totalCustomers = new AtomicInteger(0);
private static AtomicInteger servedCustomers = new AtomicInteger(0);
private static AtomicLong totalWaitingTime = new AtomicLong(0);
private static AtomicInteger maxQueueLength = new AtomicInteger(0);
// 共享队列
private static BlockingQueue<Customer> customerQueue = new LinkedBlockingQueue<>();
public static void main(String[] args) {
System.out.println("===== 银行排队系统仿真开始 =====");
System.out.println("仿真时长:" + SIMULATION_MINUTES + "分钟");
System.out.println("柜台数量:" + NUM_COUNTERS);
System.out.println("================================\n");
// 启动仿真
long startTime = System.currentTimeMillis();
long endTime = startTime + SIMULATION_MINUTES * 60 * 1000;
// 创建并启动柜台服务线程
List<Thread> counterThreads = new ArrayList<>();
for (int i = 0; i < NUM_COUNTERS; i++) {
Counter counter = new Counter("柜台-" + (i + 1));
Thread thread = new Thread(counter);
thread.setName("Counter-" + (i + 1));
thread.start();
counterThreads.add(thread);
}
// 创建客户到达生成器
CustomerGenerator generator = new CustomerGenerator(endTime);
Thread generatorThread = new Thread(generator, "CustomerGenerator");
generatorThread.start();
// 监控线程
Thread monitorThread = new Thread(new Monitor(endTime), "Monitor");
monitorThread.setDaemon(true);
monitorThread.start();
// 等待仿真结束
try {
generatorThread.join();
// 等待队列处理完剩余客户
Thread.sleep(5000);
// 停止柜台线程
Counter.shutdown();
for (Thread t : counterThreads) {
t.join(2000);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// 输出统计结果
printStatistics(startTime);
System.out.println("\n===== 仿真结束 =====");
}
/**
* 客户类
*/
static class Customer {
private final int id;
private final long arrivalTime;
private final long serviceTime;
public Customer(int id, long arrivalTime, long serviceTime) {
this.id = id;
this.arrivalTime = arrivalTime;
this.serviceTime = serviceTime;
}
public int getId() { return id; }
public long getArrivalTime() { return arrivalTime; }
public long getServiceTime() { return serviceTime; }
}
/**
* 客户到达生成器
*/
static class CustomerGenerator implements Runnable {
private final long endTime;
private final Random random = new Random();
public CustomerGenerator(long endTime) {
this.endTime = endTime;
}
@Override
public void run() {
int customerId = 0;
while (System.currentTimeMillis() < endTime) {
// 随机生成到达间隔
int interval = MIN_ARRIVE_INTERVAL +
random.nextInt(MAX_ARRIVE_INTERVAL - MIN_ARRIVE_INTERVAL + 1);
try {
Thread.sleep(interval);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
// 创建新客户并加入队列
Customer customer = new Customer(
++customerId,
System.currentTimeMillis(),
MIN_SERVICE_TIME +
random.nextInt(MAX_SERVICE_TIME - MIN_SERVICE_TIME + 1)
);
customerQueue.offer(customer);
totalCustomers.incrementAndGet();
// 更新最大队列长度
int currentQueueLength = customerQueue.size();
maxQueueLength.set(Math.max(maxQueueLength.get(), currentQueueLength));
System.out.printf("%s: 客户#%d到达 | 队列长度: %d%n",
getCurrentTime(), customerId, currentQueueLength);
}
System.out.println("客户到达生成器停止工作");
}
}
/**
* 柜台服务线程
*/
static class Counter implements Runnable {
private static final AtomicBoolean shutdownFlag = new AtomicBoolean(false);
private final String counterName;
public Counter(String counterName) {
this.counterName = counterName;
}
public static void shutdown() {
shutdownFlag.set(true);
}
@Override
public void run() {
System.out.println(counterName + " 开始服务");
while (!shutdownFlag.get() || !customerQueue.isEmpty()) {
try {
// 尝试获取客户,等待最多500毫秒
Customer customer = customerQueue.poll(500, TimeUnit.MILLISECONDS);
if (customer != null) {
// 计算等待时间
long waitingTime = System.currentTimeMillis() - customer.getArrivalTime();
totalWaitingTime.addAndGet(waitingTime);
servedCustomers.incrementAndGet();
System.out.printf("%s: %s开始服务客户#%d | 等待时间: %.2f秒%n",
getCurrentTime(), counterName, customer.getId(), waitingTime / 1000.0);
// 模拟服务时间
Thread.sleep(customer.getServiceTime());
System.out.printf("%s: %s完成服务客户#%d | 服务时间: %.2f秒%n",
getCurrentTime(), counterName, customer.getId(),
customer.getServiceTime() / 1000.0);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
}
System.out.println(counterName + " 停止服务");
}
}
/**
* 监控线程 - 定期输出系统状态
*/
static class Monitor implements Runnable {
private final long endTime;
public Monitor(long endTime) {
this.endTime = endTime;
}
@Override
public void run() {
while (System.currentTimeMillis() < endTime) {
System.out.printf(" [监控] 队列长度: %d | 已服务: %d | 总客户: %d%n",
customerQueue.size(), servedCustomers.get(), totalCustomers.get());
try {
Thread.sleep(5000); // 每5秒监控一次
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return;
}
}
}
}
/**
* 获取当前时间格式化字符串
*/
private static String getCurrentTime() {
return String.format("%tT", new Date());
}
/**
* 打印统计结果
*/
private static void printStatistics(long startTime) {
long totalTime = System.currentTimeMillis() - startTime;
System.out.println("\n===== 仿真统计结果 =====");
System.out.println("总耗时: " + totalTime / 1000 + "秒");
System.out.println("总客户数: " + totalCustomers.get());
System.out.println("已服务客户数: " + servedCustomers.get());
System.out.println("未服务客户数: " + (totalCustomers.get() - servedCustomers.get()));
if (servedCustomers.get() > 0) {
double avgWaitingTime = totalWaitingTime.get() /
(1000.0 * servedCustomers.get());
System.out.printf("平均等待时间: %.2f秒%n", avgWaitingTime);
}
System.out.println("最大队列长度: " + maxQueueLength.get());
}
}
运行结果示例
===== 银行排队系统仿真开始 =====
仿真时长:30分钟
柜台数量:5
================================
[19:30:05] 柜台-1 开始服务
[19:30:05] 柜台-2 开始服务
[19:30:05] 柜台-3 开始服务
[19:30:05] 柜台-4 开始服务
[19:30:05] 柜台-5 开始服务
[19:30:06]: 客户#1到达 | 队列长度: 1
[19:30:07]: 客户#2到达 | 队列长度: 2
[19:30:07]: 柜台-1开始服务客户#1 | 等待时间: 0.00秒
[19:30:08] [监控] 队列长度: 1 | 已服务: 1 | 总客户: 2
[19:30:08]: 客户#3到达 | 队列长度: 2
[19:30:09]: 柜台-2开始服务客户#2 | 等待时间: 0.00秒
[19:30:10]: 柜台-3开始服务客户#3 | 等待时间: 0.00秒
...
扩展版本 - 带图形界面的仿真
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.concurrent.*;
/**
* 银行排队系统 - GUI版本
*/
public class BankSimulationGUI extends JFrame {
private JTextArea logArea;
private JLabel statusLabel;
private JButton startButton;
private JButton stopButton;
private JSpinner counterSpinner;
private JSpinner durationSpinner;
private volatile boolean simulationRunning = false;
private Thread simulationThread;
private BlockingQueue<Customer> queue = new LinkedBlockingQueue<>();
private AtomicInteger totalCustomers = new AtomicInteger(0);
private AtomicInteger servedCustomers = new AtomicInteger(0);
public BankSimulationGUI() {
setTitle("银行排队系统仿真");
setSize(800, 600);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
initComponents();
layoutComponents();
}
private void initComponents() {
logArea = new JTextArea();
logArea.setEditable(false);
logArea.setFont(new Font("Monospaced", Font.PLAIN, 12));
statusLabel = new JLabel("状态: 就绪");
startButton = new JButton("开始仿真");
stopButton = new JButton("停止仿真");
stopButton.setEnabled(false);
counterSpinner = new JSpinner(new SpinnerNumberModel(5, 1, 10, 1));
durationSpinner = new JSpinner(new SpinnerNumberModel(5, 1, 60, 1));
startButton.addActionListener(e -> startSimulation());
stopButton.addActionListener(e -> stopSimulation());
}
private void layoutComponents() {
setLayout(new BorderLayout());
// 控制面板
JPanel controlPanel = new JPanel(new FlowLayout());
controlPanel.add(new JLabel("柜台数:"));
controlPanel.add(counterSpinner);
controlPanel.add(new JLabel("仿真时长(秒):"));
controlPanel.add(durationSpinner);
controlPanel.add(startButton);
controlPanel.add(stopButton);
controlPanel.add(statusLabel);
add(controlPanel, BorderLayout.NORTH);
add(new JScrollPane(logArea), BorderLayout.CENTER);
}
private void startSimulation() {
if (simulationRunning) return;
simulationRunning = true;
startButton.setEnabled(false);
stopButton.setEnabled(true);
statusLabel.setText("状态: 仿真进行中");
int counters = (Integer) counterSpinner.getValue();
int duration = (Integer) durationSpinner.getValue();
simulationThread = new Thread(() -> runSimulation(counters, duration));
simulationThread.start();
}
private void stopSimulation() {
simulationRunning = false;
startButton.setEnabled(true);
stopButton.setEnabled(false);
statusLabel.setText("状态: 已停止");
}
private void runSimulation(int numCounters, int durationSeconds) {
long startTime = System.currentTimeMillis();
long endTime = startTime + durationSeconds * 1000;
// 创建柜台线程
for (int i = 0; i < numCounters; i++) {
final int counterId = i + 1;
new Thread(() -> {
while (simulationRunning && System.currentTimeMillis() < endTime) {
try {
Customer customer = queue.poll(500, TimeUnit.MILLISECONDS);
if (customer != null) {
appendLog(String.format("[%s] 柜台#%d开始服务客户#%d",
getTime(), counterId, customer.id));
Thread.sleep(customer.serviceTime);
servedCustomers.incrementAndGet();
appendLog(String.format("[%s] 柜台#%d完成客户#%d | 已服务: %d",
getTime(), counterId, customer.id, servedCustomers.get()));
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}, "Counter-" + i).start();
}
// 生成客户
int customerId = 0;
Random random = new Random();
while (simulationRunning && System.currentTimeMillis() < endTime) {
try {
Thread.sleep(500 + random.nextInt(1500));
Customer customer = new Customer(
++customerId,
System.currentTimeMillis(),
500 + random.nextInt(2000)
);
queue.offer(customer);
totalCustomers.incrementAndGet();
appendLog(String.format("[%s] 客户#%d到达 | 队列长度: %d",
getTime(), customerId, queue.size()));
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
// 等待队列清空
appendLog("客户生成停止,等待队列清空...");
while (!queue.isEmpty() && simulationRunning) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
SwingUtilities.invokeLater(() -> {
statusLabel.setText("状态: 仿真完成");
startButton.setEnabled(true);
stopButton.setEnabled(false);
appendLog(String.format("仿真完成! 总客户: %d | 已服务: %d",
totalCustomers.get(), servedCustomers.get()));
});
}
private void appendLog(String message) {
SwingUtilities.invokeLater(() -> {
logArea.append(message + "\n");
logArea.setCaretPosition(logArea.getDocument().getLength());
});
}
private String getTime() {
return String.format("%tT", new Date());
}
static class Customer {
final int id;
final long arrivalTime;
final long serviceTime;
Customer(int id, long arrivalTime, long serviceTime) {
this.id = id;
this.arrivalTime = arrivalTime;
this.serviceTime = serviceTime;
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
new BankSimulationGUI().setVisible(true);
});
}
}
仿真案例说明
核心概念:
- 生产者-消费者模式 - 客户生成器(生产者)和柜台服务(消费者)
- 线程同步 - 使用BlockingQueue实现并发安全的队列
- 原子变量 - AtomicInteger/AtomicLong用于并发计数
- 线程生命周期 - 优雅关闭和线程join
关键设计模式:
- 并发队列:LinkedBlockingQueue作为共享数据缓冲区
- 随机模拟:使用Random类模拟真实的到达和服务时间
- 监控机制:实时查看系统状态
- 统计收集:记录关键性能指标
可扩展方向:
- 添加VIP客户优先级队列
- 实现多个服务类型(存款/取款/贷款)
- 添加动态调整柜台数量策略
- 集成实时图表展示(JavaFX)
- 支持参数配置(通过配置文件)
这个仿真案例展示了Java多线程编程的核心技术和设计模式,可以用于教学或实际的排队系统模拟分析。