Java中实现线程叫号看病的模拟,可以通过多线程技术来模拟病人挂号、排队等待以及医生叫号看病的过程,下面将详细介绍如何实现这一过程,包括关键类的设计、线程的使用以及同步机制的应用。
系统设计
整个叫号系统可以分为以下几个主要部分:
- 病人类(Patient):表示每个病人,包含病人的编号、姓名等信息。
- 挂号类(Registration):负责生成病人编号,并将病人加入候诊队列。
- 候诊区类(WaitingRoom):使用队列数据结构管理等待看病的病人。
- 医生类(Doctor):负责从候诊区中取出病人号码进行治疗。
- 叫号机类(CallingMachine):模拟叫号的过程,按照一定的规则叫号。
- 看病过程类(TreatmentProcess):模拟医生看病的过程,包括处理特需号和普通号的逻辑。
关键类的设计
1 病人类(Patient)
public class Patient { private int number; private String name; private boolean isSpecial; // 是否为特需号 public Patient(int number, String name, boolean isSpecial) { this.number = number; this.name = name; this.isSpecial = isSpecial; } public int getNumber() { return number; } public String getName() { return name; } public boolean isSpecial() { return isSpecial; } }
2 挂号类(Registration)
import java.util.concurrent.atomic.AtomicInteger; public class Registration { private AtomicInteger atomicInteger; public Registration() { this.atomicInteger = new AtomicInteger(1); } public int generateNumber() { return atomicInteger.getAndIncrement(); } }
3 候诊区类(WaitingRoom)
import java.util.Queue; import java.util.concurrent.ArrayBlockingQueue; public class WaitingRoom { private Queue<Patient> queue; public WaitingRoom(int capacity) { this.queue = new ArrayBlockingQueue<>(capacity); } public void addPatient(Patient patient) throws InterruptedException { queue.add(patient); System.out.println("Patient " + patient.getName() + " with number " + patient.getNumber() + " is waiting in the waiting room."); } public Patient getNextPatient() throws InterruptedException { Patient patient = queue.poll(); if (patient != null) { System.out.println("Doctor is calling patient number: " + patient.getNumber() + ", Name: " + patient.getName()); } return patient; } }
4 医生类(Doctor)
public class Doctor implements Runnable { private WaitingRoom waitingRoom; private boolean isRunning; public Doctor(WaitingRoom waitingRoom) { this.waitingRoom = waitingRoom; this.isRunning = true; } @Override public void run() { while (isRunning) { try { Patient patient = waitingRoom.getNextPatient(); if (patient != null) { // 模拟看病时间 int treatmentTime = patient.isSpecial() ? 2000 : 1000; // 特需号看病时间是普通号的2倍 Thread.sleep(treatmentTime); System.out.println("Finished treating patient number: " + patient.getNumber()); } else { // 如果没有病人,医生休息一会儿 Thread.sleep(500); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } public void stop() { isRunning = false; } }
5 叫号机类(CallingMachine)
public class CallingMachine implements Runnable { private WaitingRoom waitingRoom; private Registration registration; private boolean isRunning; private int ordinaryCount = 0; // 普通号已叫号数量 private int specialCount = 0; // 特需号已叫号数量 private final int MAX_ORDINARY = 20; // 普通号总数 private final int MAX_SPECIAL = 10; // 特需号总数 public CallingMachine(WaitingRoom waitingRoom, Registration registration) { this.waitingRoom = waitingRoom; this.registration = registration; this.isRunning = true; } @Override public void run() { while (isRunning) { try { // 优先叫特需号,直到特需号叫完或者普通号叫到第10号 if (specialCount < MAX_SPECIAL && (ordinaryCount < 10 || specialCount < MAX_SPECIAL)) { int number = registration.generateNumber(); boolean isSpecial = number <= MAX_SPECIAL; // 假设前10个号为特需号 Patient patient = new Patient(number, "Patient" + number, isSpecial); waitingRoom.addPatient(patient); if (isSpecial) { specialCount++; } else { ordinaryCount++; } } else if (ordinaryCount < MAX_ORDINARY) { // 普通号叫号,但需要先叫完特需号 int number = registration.generateNumber(); Patient patient = new Patient(number, "Patient" + number, false); waitingRoom.addPatient(patient); ordinaryCount++; } else { // 所有号都已叫完,停止叫号 isRunning = false; } Thread.sleep(500); // 模拟叫号间隔 } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } } public void stop() { isRunning = false; } }
6 医院类(Hospital)
public class Hospital { private WaitingRoom waitingRoom; private Registration registration; private Doctor doctor; private CallingMachine callingMachine; private Thread doctorThread; private Thread callingMachineThread; public Hospital(int waitingRoomCapacity) { this.waitingRoom = new WaitingRoom(waitingRoomCapacity); this.registration = new Registration(); this.doctor = new Doctor(waitingRoom); this.callingMachine = new CallingMachine(waitingRoom, registration); } public void start() { doctorThread = new Thread(doctor); callingMachineThread = new Thread(callingMachine); doctorThread.start(); callingMachineThread.start(); } public void stop() { callingMachine.stop(); doctor.stop(); try { doctorThread.join(); callingMachineThread.join(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } public static void main(String[] args) { Hospital hospital = new Hospital(30); // 候诊区容量为30 hospital.start(); } }
同步机制与线程安全
在上述实现中,WaitingRoom
类使用了ArrayBlockingQueue
来保证线程安全,确保多个线程可以安全地添加和获取病人。Registration
类使用了AtomicInteger
来生成唯一的病人编号,避免了多线程环境下的竞争问题。Doctor
和CallingMachine
类中的isRunning
标志位用于控制线程的停止,确保在需要时可以安全地停止线程。
运行效果与逻辑说明
运行程序后,可以看到挂号系统生成病人号码并加入候诊区,医生叫号后从候诊区取出病人号码,模拟了实际看病的流程,具体逻辑如下:
- 挂号与排队:
CallingMachine
线程不断生成病人号码,并根据规则将病人加入候诊区,特需号优先于普通号,直到特需号叫完或者普通号叫到第10号,之后,继续叫普通号,直到所有号叫完。 - 医生叫号与看病:
Doctor
线程不断从候诊区中取出病人号码,模拟看病过程,特需号的看病时间是普通号的2倍,医生在没有病人时会休息一会儿,避免空转。 - 线程停止:当所有号都叫完后,
CallingMachine
线程停止生成号码,Doctor
线程在处理完所有病人后自动停止。Hospital
类的stop
方法确保所有线程都安全停止。
相关问答FAQs
Q1:如何确保特需号优先于普通号?
A1:在CallingMachine
类中,通过判断当前已叫的特需号数量和普通号数量,优先生成特需号,直到特需号叫完或者普通号叫到第10号,这样可以确保特需号优先于普通号。
Q2:如何处理医生在看病过程中的中断?
A2:在Doctor
类的run
方法中,使用try-catch
块捕获InterruptedException
异常,并在捕获到异常时调用Thread.currentThread().interrupt()
方法,确保线程的中断状态被正确设置,这样,当外部调用stop
方法时,医生
原创文章,发布者:酷盾叔,转转请注明出处:https://www.kd.cn/ask/48556.html