计算机底层技术学习之进程(或线程)调度-最合适类比的场景是医院就诊流程-挂号_开检查单_缴费_看检查结果_开药
Java NIO 核心概念 vs 医院系统映射
flowchart TB
subgraph Java NIO
Selector[Selector<br>分诊台]
Channel[Channel<br>患者通道]
Buffer[Buffer<br>病历本]
SelectionKey[SelectionKey<br>就诊登记]
end
subgraph 医院系统
分诊台[分诊台]
患者通道[患者就诊通道]
病历本[电子病历本]
就诊登记[就诊登记卡]
end
Selector --> 分诊台
Channel --> 患者通道
Buffer --> 病历本
SelectionKey --> 就诊登记
详细映射关系说明:
| Java NIO 组件 | 医院系统对应物 | 功能说明 |
|---|---|---|
| Selector | 智能分诊台 | 监控所有患者状态,调度就绪的患者到对应科室 |
| ServerSocketChannel | 医院挂号窗口 | 接收新患者连接(OP_ACCEPT) |
| SocketChannel | 患者就诊通道 | 每个患者独立的诊疗通道(包含OP_READ/OP_WRITE状态) |
| SelectionKey | 就诊登记卡 | 记录患者当前状态(挂号/待诊/检查中/取药中)和关联的诊疗档案 |
| ByteBuffer | 电子病历本 | 存储患者症状描述和医生处方(通过flip()切换读写模式) |
| OP_ACCEPT | 新患者到达 | 触发挂号流程 |
| OP_READ | 患者描述症状 | 医生可读取患者信息 |
| OP_WRITE | 开具处方 | 医生可向患者发送处方/检查单 |
完整就诊流程代码实现
// 创建医院系统
Selector triageDesk = Selector.open(); // 智能分诊台
ServerSocketChannel registrationDesk = ServerSocketChannel.open(); // 挂号窗口
registrationDesk.bind(new InetSocketAddress(8080));
registrationDesk.configureBlocking(false);
registrationDesk.register(triageDesk, SelectionKey.OP_ACCEPT); // 监听新患者
while (true) {
// 分诊台轮询(500ms超时)
int readyPatients = triageDesk.select(500);
if (readyPatients == 0) continue;
// 处理就绪患者
Set<SelectionKey> activeCases = triageDesk.selectedKeys();
Iterator<SelectionKey> caseIterator = activeCases.iterator();
while (caseIterator.hasNext()) {
SelectionKey caseKey = caseIterator.next();
caseIterator.remove();
if (caseKey.isAcceptable()) {
// ======= 新患者挂号 =======
SocketChannel patient = registrationDesk.accept();
patient.configureBlocking(false);
// 发放病历本(初始1024容量)
ByteBuffer medicalRecord = ByteBuffer.allocate(1024);
// 登记到分诊台(初始关注读取症状)
patient.register(triageDesk, SelectionKey.OP_READ, medicalRecord);
} else if (caseKey.isReadable()) {
// ======= 患者描述症状 =======
SocketChannel patient = (SocketChannel) caseKey.channel();
ByteBuffer record = (ByteBuffer) caseKey.attachment();
int bytesRead = patient.read(record);
if (bytesRead == -1) { // 患者离开
patient.close();
continue;
}
if (bytesRead > 0) {
record.flip(); // 切换病历为读模式
// 解析症状(实际业务处理)
processSymptoms(record);
record.clear();
// 变更状态:待开具处方
caseKey.interestOps(SelectionKey.OP_WRITE);
}
} else if (caseKey.isWritable()) {
// ======= 医生开具处方 =======
SocketChannel patient = (SocketChannel) caseKey.channel();
ByteBuffer record = (ByteBuffer) caseKey.attachment();
// 生成处方(实际业务逻辑)
String prescription = generatePrescription();
record.put(prescription.getBytes());
record.flip(); // 准备写模式
// 发送处方
while (record.hasRemaining()) {
patient.write(record);
}
record.clear();
// 变更状态:等待下次就诊
caseKey.interestOps(SelectionKey.OP_READ);
}
}
}
// 症状处理方法
void processSymptoms(ByteBuffer record) {
String symptoms = StandardCharsets.UTF_8.decode(record).toString();
System.out.println("诊断症状: " + symptoms);
// 这里可添加实际业务逻辑...
}
// 处方生成方法
String generatePrescription() {
// 这里可添加实际业务逻辑...
return "处方:\n- 维生素C 100mg/日\n- 休息3天";
}
关键流程解析
-
挂号阶段 (OP_ACCEPT)
patient.register(triageDesk, SelectionKey.OP_READ, medicalRecord);- 新患者获得病历本(Buffer)
- 初始关注"可读"状态(等待描述症状)
-
就诊阶段 (OP_READ)
patient.read(record); // 读取症状 record.flip(); // 切换为读模式 processSymptoms(record); // 业务处理 record.clear(); // 重置病历本 -
处方阶段 (OP_WRITE)
record.put(prescription.getBytes()); // 写入处方 record.flip(); // 切换为写模式 patient.write(record); // 发送给患者 -
状态转换
// 就诊完成 → 准备开处方 caseKey.interestOps(SelectionKey.OP_WRITE); // 处方完成 → 准备下次就诊 caseKey.interestOps(SelectionKey.OP_READ);
高级优化技巧(资深开发者关注点)
-
内存池优化
// 复用病历本(避免频繁创建) ByteBuffer record = ByteBuffer.allocateDirect(2048); // 堆外内存 -
背压控制
// 当处方队列过长时暂停接收新症状 if (pendingPrescriptions > 100) { patient.register(triageDesk, 0); // 暂停所有事件 } -
零拷贝化验单
// 检查报告直接传输(避免复制) FileChannel labReport = new FileInputStream("xray.jpg").getChannel(); labReport.transferTo(0, labReport.size(), patient); -
急诊绿色通道
// 高优先级患者 patient.setOption(StandardSocketOptions.SO_PRIORITY, 10);
这个映射体系展示了NIO如何像现代化医院一样,通过状态监控+资源复用+流程优化实现高效处理。Selector作为智能分诊台,避免医生(线程)空等;Buffer作为电子病历,避免数据反复拷贝;Channel作为独立就诊通道,保证诊疗过程隔离性。
浙公网安备 33010602011771号