计算机底层技术学习之进程(或线程)调度-最合适类比的场景是医院就诊流程-挂号_开检查单_缴费_看检查结果_开药

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天";
}

关键流程解析

  1. 挂号阶段 (OP_ACCEPT)

    patient.register(triageDesk, SelectionKey.OP_READ, medicalRecord);
    
    • 新患者获得病历本(Buffer)
    • 初始关注"可读"状态(等待描述症状)
  2. 就诊阶段 (OP_READ)

    patient.read(record);  // 读取症状
    record.flip();         // 切换为读模式
    processSymptoms(record); // 业务处理
    record.clear();        // 重置病历本
    
  3. 处方阶段 (OP_WRITE)

    record.put(prescription.getBytes()); // 写入处方
    record.flip();                       // 切换为写模式
    patient.write(record);               // 发送给患者
    
  4. 状态转换

    // 就诊完成 → 准备开处方
    caseKey.interestOps(SelectionKey.OP_WRITE);
    
    // 处方完成 → 准备下次就诊
    caseKey.interestOps(SelectionKey.OP_READ);
    

高级优化技巧(资深开发者关注点)

  1. 内存池优化

    // 复用病历本(避免频繁创建)
    ByteBuffer record = ByteBuffer.allocateDirect(2048); // 堆外内存
    
  2. 背压控制

    // 当处方队列过长时暂停接收新症状
    if (pendingPrescriptions > 100) {
        patient.register(triageDesk, 0); // 暂停所有事件
    }
    
  3. 零拷贝化验单

    // 检查报告直接传输(避免复制)
    FileChannel labReport = new FileInputStream("xray.jpg").getChannel();
    labReport.transferTo(0, labReport.size(), patient);
    
  4. 急诊绿色通道

    // 高优先级患者
    patient.setOption(StandardSocketOptions.SO_PRIORITY, 10);
    

这个映射体系展示了NIO如何像现代化医院一样,通过状态监控+资源复用+流程优化实现高效处理。Selector作为智能分诊台,避免医生(线程)空等;Buffer作为电子病历,避免数据反复拷贝;Channel作为独立就诊通道,保证诊疗过程隔离性。

posted @ 2025-06-01 00:59  gongchengship  阅读(18)  评论(0)    收藏  举报