BIO、NIO 和 AIO 基础介绍

BIO、NIO 和 AIO 基础介绍

在 Java 网络编程中,BIO、NIO、AIO 是三种核心的 I/O 模型,分别对应不同的阻塞/非阻塞、同步/异步特性,适用于不同的业务场景。

一、核心概念

1.1 基本定义

  • BIO:同步阻塞 I/O(Blocking I/O)
  • NIO:同步非阻塞 I/O(Non-blocking I/O),也叫 New I/O,核心是「多路复用」
  • AIO:异步非阻塞 I/O(Asynchronous I/O),也叫 NIO 2.0

1.2 重要概念区分

同步/异步 关注的是「是否需要等待 I/O 操作完成」

  • 同步:线程主动等待 I/O 结果,直到操作完成
  • 异步:线程无需等待,I/O 完成后由系统回调通知

阻塞/非阻塞 关注的是「等待时线程是否被挂起」

  • 阻塞:线程在 I/O 过程中被挂起,无法做其他事
  • 非阻塞:线程在 I/O 过程中不挂起,可继续执行其他逻辑

1.3 三种模型对比速览

模型 同步/异步 阻塞/非阻塞 线程模型 适用场景
BIO 同步 阻塞 一连接一线程 连接数少、低并发
NIO 同步 非阻塞 单线程处理多连接 高并发、短连接
AIO 异步 非阻塞 回调机制、无需轮询 高并发、长耗时 I/O

二、BIO(同步阻塞 I/O)

2.1 核心特点

  • 工作原理:线程发起 I/O 请求后,必须阻塞等待 I/O 操作完成(如读取数据、写入数据),期间线程无法做任何事;
  • 线程模型:每处理一个连接需要一个独立线程,连接数多的时候会导致线程数暴涨,性能瓶颈明显;
  • 编程模型:简单直观,适合连接数少、单次操作耗时短的场景(如简单的客户端-服务器通信)。

2.2 BIO 工作流程图

flowchart LR Client1[客户端1] --> Server[服务器主线程] Client2[客户端2] --> Server Client3[客户端3] --> Server Server --> Thread1[线程1] Server --> Thread2[线程2] Server --> Thread3[线程3] Thread1 --> Block1[阻塞等待数据] Thread2 --> Block2[阻塞等待数据] Thread3 --> Block3[阻塞等待数据] Block1 --> Process1[处理数据] Block2 --> Process2[处理数据] Block3 --> Process3[处理数据] style Block1 fill:#f96 style Block2 fill:#f96 style Block3 fill:#f96

2.3 代码示例

(1)BIO 服务器
java 复制代码
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * BIO 同步阻塞服务器示例(优化后:使用线程池)
 * 每一个客户端连接对应一个线程,线程阻塞等待数据读取
 */
public class BioServer {
    private static final int PORT = 8080;
    private static final int MAX_THREADS = 100;
    
    public static void main(String[] args) throws IOException {
        // 使用线程池限制线程数量,避免无限创建线程
        ExecutorService threadPool = Executors.newFixedThreadPool(MAX_THREADS);
        
        try (ServerSocket serverSocket = new ServerSocket(PORT)) {
            System.out.println("BIO 服务器已启动,监听端口 " + PORT + "...");
            System.out.println("最大并发线程数:" + MAX_THREADS);

            while (true) {
                // 阻塞点1:accept() 阻塞直到有客户端连接
                Socket socket = serverSocket.accept();
                System.out.println("新客户端连接:" + socket.getInetAddress() + 
                                 ":" + socket.getPort());

                // 将连接提交给线程池处理
                threadPool.submit(new ClientHandler(socket));
            }
        }
    }
    
    /**
     * 客户端处理器(每个连接一个任务)
     */
    static class ClientHandler implements Runnable {
        private final Socket socket;
        
        public ClientHandler(Socket socket) {
            this.socket = socket;
        }
        
        @Override
        public void run() {
            try (InputStream inputStream = socket.getInputStream()) {
                byte[] buffer = new byte[1024];
                while (true) {
                    // 阻塞点2:read() 阻塞直到有数据可读
                    int len = inputStream.read(buffer);
                    if (len == -1) { // 客户端关闭连接
                        System.out.println("客户端断开连接:" + 
                                         socket.getInetAddress() + ":" + socket.getPort());
                        break;
                    }
                    String msg = new String(buffer, 0, len);
                    System.out.println("[" + Thread.currentThread().getName() + 
                                     "] 收到消息:" + msg);
                    
                    // TODO: 业务处理
                    
                    // 模拟处理耗时
                    Thread.sleep(100);
                }
            } catch (IOException | InterruptedException e) {
                e.printStackTrace();
            } finally {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
(2)BIO 客户端
java 复制代码
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

/**
 * BIO 客户端示例
 */
public class BioClient {
    private static final String SERVER_HOST = "localhost";
    private static final int SERVER_PORT = 8080;
    
    public static void main(String[] args) {
        try (Socket socket = new Socket(SERVER_HOST, SERVER_PORT);
             OutputStream outputStream = socket.getOutputStream();
             Scanner scanner = new Scanner(System.in)) {
            
            System.out.println("已连接到服务器 " + SERVER_HOST + ":" + SERVER_PORT);
            System.out.println("请输入要发送的消息(输入 'exit' 退出):");
            
            while (true) {
                System.out.print("> ");
                String msg = scanner.nextLine();
                
                if ("exit".equalsIgnoreCase(msg)) {
                    break;
                }
                
                // 发送数据(阻塞,直到数据写入完成)
                outputStream.write(msg.getBytes());
                outputStream.flush();
                System.out.println("消息已发送");
            }
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("客户端已关闭");
    }
}

2.4 BIO 优缺点

优点 缺点
编程模型简单,易于理解和实现 线程资源消耗大,连接数多时性能急剧下降
代码调试方便,执行流程清晰 线程阻塞造成资源浪费,CPU 利用率低
适合低并发、小数据量场景 系统稳定性差,容易因线程过多导致宕机

三、NIO(同步非阻塞 I/O)

3.1 核心特点

  • 工作原理:线程发起 I/O 请求后,无需阻塞等待,可先去处理其他任务,定期轮询查看 I/O 是否完成;
  • 核心组件
    • Channel(通道):双向读写,替代 BIO 的 Stream
    • Buffer(缓冲区):数据读写的载体
    • Selector(多路复用器):核心组件,单线程监听多个 Channel 的事件
  • 多路复用:一个 Selector 可以监听多个 Channel 的事件(连接、读、写),单个线程就能处理大量连接,解决 BIO 线程膨胀问题;
  • 适用场景:连接数多、单次操作耗时短的场景(如高并发的 Web 服务器)。

3.2 NIO 多路复用核心流程图

flowchart TD A["创建 ServerSocketChannel"] --> B["配置为非阻塞模式"] B --> C["绑定监听端口"] C --> D["创建 Selector(多路复用器)"] D --> E["将 ServerSocketChannel 注册到 Selector,关注 ACCEPT 事件"] E --> F["Selector 轮询就绪事件 select()"] F --> G{"是否有就绪事件?"} G -- 无 --> F G -- 有 --> H["获取就绪的 SelectionKey 集合"] H --> I["遍历 SelectionKey 集合"] I --> J{判断事件类型} J -- ACCEPT新连接--> K["通过 ServerSocketChannel 接收 SocketChannel"] K --> L["配置 SocketChannel 为非阻塞模式"] L --> M["将 SocketChannel 注册到 Selector,关注 READ 事件"] M --> F J -- READ可读--> N["通过 SocketChannel 读取数据到 Buffer"] N --> O["处理业务逻辑"] O --> P{"是否需要返回数据?"} P -- 是 --> Q["修改关注事件为 WRITE"] Q --> F P -- 否 --> F J -- WRITE可写--> R["通过 SocketChannel 写入 Buffer 数据"] R --> S{"数据写入完成?"} S -- 是 --> T["修改关注事件为 READ"] T --> F S -- 否 --> R

3.3 NIO 代码示例

java 复制代码
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * NIO 多路复用服务器示例(完整版)
 * 单个线程通过 Selector 处理所有客户端连接和读写事件
 */
public class NioServer {
    private static final int PORT = 8080;
    private static final int BUFFER_SIZE = 1024;
    private static final long SELECTOR_TIMEOUT = 1000; // 1秒超时
    
    // 统计在线客户端数
    private static final ConcurrentHashMap<SocketChannel, String> clients = 
        new ConcurrentHashMap<>();
    
    public static void main(String[] args) {
        try {
            new NioServer().start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    public void start() throws IOException {
        // 1. 创建 ServerSocketChannel
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        
        // 2. 配置为非阻塞模式
        serverSocketChannel.configureBlocking(false);
        
        // 3. 绑定端口
        serverSocketChannel.bind(new InetSocketAddress(PORT));
        System.out.println("NIO 服务器已启动,监听端口 " + PORT + "...");
        
        // 4. 创建 Selector
        Selector selector = Selector.open();
        
        // 5. 注册 ServerSocketChannel 到 Selector,关注 ACCEPT 事件
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        
        // 6. 主循环:处理就绪事件
        while (true) {
            // 阻塞等待就绪事件(带超时)
            int readyChannels = selector.select(SELECTOR_TIMEOUT);
            
            if (readyChannels == 0) {
                continue; // 无就绪事件,继续轮询
            }
            
            // 获取所有就绪的 SelectionKey
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            
            // 遍历处理每个就绪事件
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                iterator.remove(); // 必须移除,避免重复处理
                
                try {
                    // 处理事件
                    if (!key.isValid()) {
                        continue;
                    }
                    
                    if (key.isAcceptable()) {
                        handleAccept(key, selector);
                    } else if (key.isReadable()) {
                        handleRead(key);
                    } else if (key.isWritable()) {
                        handleWrite(key);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    // 异常时关闭连接
                    key.cancel();
                    closeChannel(key.channel());
                }
            }
            
            // 可选:打印在线客户端数
            System.out.println("当前在线客户端数:" + clients.size());
        }
    }
    
    /**
     * 处理新连接
     */
    private void handleAccept(SelectionKey key, Selector selector) throws IOException {
        ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
        
        // 接收新连接(非阻塞)
        SocketChannel socketChannel = serverChannel.accept();
        if (socketChannel == null) return;
        
        // 配置为非阻塞模式
        socketChannel.configureBlocking(false);
        
        // 注册 READ 事件
        socketChannel.register(selector, SelectionKey.OP_READ, 
                              ByteBuffer.allocate(BUFFER_SIZE));
        
        // 记录客户端
        String clientInfo = socketChannel.getRemoteAddress().toString();
        clients.put(socketChannel, clientInfo);
        System.out.println("新客户端连接:" + clientInfo);
        System.out.println("当前在线客户端数:" + clients.size());
    }
    
    /**
     * 处理读事件
     */
    private void handleRead(SelectionKey key) throws IOException {
        SocketChannel socketChannel = (SocketChannel) key.channel();
        ByteBuffer buffer = (ByteBuffer) key.attachment();
        
        // 读取数据(非阻塞)
        int bytesRead = socketChannel.read(buffer);
        
        if (bytesRead == -1) {
            // 客户端关闭连接
            String clientInfo = clients.remove(socketChannel);
            System.out.println("客户端断开连接:" + clientInfo);
            key.cancel();
            closeChannel(socketChannel);
            return;
        }
        
        if (bytesRead > 0) {
            // 切换到读模式
            buffer.flip();
            
            // 读取数据
            byte[] data = new byte[buffer.limit()];
            buffer.get(data);
            String message = new String(data).trim();
            
            // 获取客户端信息
            String clientInfo = clients.get(socketChannel);
            System.out.println("收到来自 " + clientInfo + " 的消息:" + message);
            
            // 清空缓冲区,准备下次读取
            buffer.clear();
            
            // 准备响应数据
            String response = "服务器已收到: " + message;
            ByteBuffer responseBuffer = ByteBuffer.wrap(response.getBytes());
            
            // 如果需要返回数据,修改关注事件为 WRITE
            key.interestOps(SelectionKey.OP_WRITE);
            key.attach(responseBuffer);
        }
    }
    
    /**
     * 处理写事件
     */
    private void handleWrite(SelectionKey key) throws IOException {
        SocketChannel socketChannel = (SocketChannel) key.channel();
        ByteBuffer buffer = (ByteBuffer) key.attachment();
        
        // 写入数据(非阻塞)
        socketChannel.write(buffer);
        
        if (!buffer.hasRemaining()) {
            // 数据写入完成,重新关注 READ 事件
            key.interestOps(SelectionKey.OP_READ);
            key.attach(ByteBuffer.allocate(BUFFER_SIZE));
        }
    }
    
    /**
     * 关闭通道
     */
    private void closeChannel(Channel channel) {
        if (channel != null && channel.isOpen()) {
            try {
                channel.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

3.4 NIO 优缺点

优点 缺点
单线程可处理大量连接,资源消耗小 编程复杂度高,需要处理各种边界情况
高并发下性能优秀,CPU 利用率高 调试会比较困难,容易出现 bug
数据读写灵活,可精确控制缓冲区 需要处理半包/粘包问题

四、AIO(异步非阻塞 I/O)

4.1 核心特点

  • 工作原理:线程发起 I/O 请求后,直接返回,无需轮询,I/O 操作由操作系统完成后,通过回调函数通知线程处理结果;
  • 核心组件
    • AsynchronousServerSocketChannel:异步服务器通道
    • AsynchronousSocketChannel:异步客户端通道
    • CompletionHandler:回调处理器
  • 优势:无需手动多路复用,由系统底层完成,编程模型更简洁;
  • 适用场景:连接数多、单次操作耗时长的场景(如文件下载、大数据传输)。

4.2 AIO 工作流程图

sequenceDiagram participant App as 应用程序 participant Kernel as 操作系统内核 participant Callback as 回调处理器 App->>Kernel: 1. 发起异步读操作 Note over App: 立即返回,不阻塞 App->>App: 2. 继续执行其他任务 Kernel->>Kernel: 3. 内核准备数据 Kernel->>Kernel: 4. 内核将数据拷贝到缓冲区 Kernel->>Callback: 5. I/O 完成,触发回调 Callback->>App: 6. 处理数据 Note over App,Kernel: 整个过程应用程序无需阻塞等待

4.3 AIO 代码示例

java 复制代码
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * AIO 异步非阻塞服务器示例(完整版)
 * 基于回调处理连接和读写事件,无需轮询
 */
public class AioServer {
    private static final int PORT = 8080;
    private static final int BUFFER_SIZE = 1024;
    private static final ConcurrentHashMap<AsynchronousSocketChannel, String> clients = 
        new ConcurrentHashMap<>();
    
    // 用于处理回调的业务线程池
    private ExecutorService businessThreadPool = Executors.newFixedThreadPool(10);
    
    public static void main(String[] args) {
        try {
            new AioServer().start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    public void start() throws IOException {
        // 1. 创建异步服务器通道
        AsynchronousServerSocketChannel serverChannel = 
            AsynchronousServerSocketChannel.open();
        
        // 2. 绑定端口
        serverChannel.bind(new InetSocketAddress(PORT));
        System.out.println("AIO 服务器已启动,监听端口 " + PORT + "...");
        
        // 3. 异步接收连接
        serverChannel.accept(null, new AcceptCompletionHandler(serverChannel));
        
        // 4. 防止主线程退出
        try {
            Thread.currentThread().join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            businessThreadPool.shutdown();
        }
    }
    
    /**
     * 连接接收回调处理器
     */
    class AcceptCompletionHandler implements 
            CompletionHandler<AsynchronousSocketChannel, Void> {
        
        private final AsynchronousServerSocketChannel serverChannel;
        
        public AcceptCompletionHandler(AsynchronousServerSocketChannel serverChannel) {
            this.serverChannel = serverChannel;
        }
        
        @Override
        public void completed(AsynchronousSocketChannel socketChannel, Void attachment) {
            // 立即再次接收新连接(关键:必须再次调用accept,形成循环)
            serverChannel.accept(null, this);
            
            try {
                // 处理新连接
                String clientInfo = socketChannel.getRemoteAddress().toString();
                clients.put(socketChannel, clientInfo);
                System.out.println("新客户端连接:" + clientInfo);
                System.out.println("当前在线客户端数:" + clients.size());
                
                // 创建缓冲区
                ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
                
                // 异步读取数据
                socketChannel.read(buffer, buffer, new ReadCompletionHandler(socketChannel));
                
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
        @Override
        public void failed(Throwable exc, Void attachment) {
            System.err.println("接收连接失败:" + exc.getMessage());
            // 继续接收(失败后重试)
            serverChannel.accept(null, this);
        }
    }
    
    /**
     * 读取数据回调处理器
     */
    class ReadCompletionHandler implements 
            CompletionHandler<Integer, ByteBuffer> {
        
        private final AsynchronousSocketChannel socketChannel;
        
        public ReadCompletionHandler(AsynchronousSocketChannel socketChannel) {
            this.socketChannel = socketChannel;
        }
        
        @Override
        public void completed(Integer bytesRead, ByteBuffer buffer) {
            if (bytesRead == -1) {
                // 客户端关闭连接
                String clientInfo = clients.remove(socketChannel);
                System.out.println("客户端断开连接:" + clientInfo);
                try {
                    socketChannel.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return;
            }
            
            if (bytesRead > 0) {
                // 切换到读模式
                buffer.flip();
                
                // 读取数据
                byte[] data = new byte[buffer.limit()];
                buffer.get(data);
                String message = new String(data).trim();
                
                // 获取客户端信息
                String clientInfo = clients.get(socketChannel);
                
                // 业务处理(提交到业务线程池,避免阻塞回调线程)
                businessThreadPool.submit(() -> {
                    try {
                        System.out.println("收到来自 " + clientInfo + " 的消息:" + message);
                        
                        // 模拟业务处理
                        String processedMsg = processMessage(message);
                        
                        // 准备响应
                        String response = "服务器响应: " + processedMsg;
                        ByteBuffer responseBuffer = ByteBuffer.wrap(response.getBytes());
                        
                        // 异步写入响应
                        socketChannel.write(responseBuffer, null, 
                            new WriteCompletionHandler(socketChannel, buffer));
                        
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                });
            }
        }
        
        @Override
        public void failed(Throwable exc, ByteBuffer buffer) {
            System.err.println("读取数据失败:" + exc.getMessage());
            try {
                socketChannel.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        
        /**
         * 模拟消息处理
         */
        private String processMessage(String message) {
            // TODO: 实际的业务处理
            return "processed: " + message;
        }
    }
    
    /**
     * 写入数据回调处理器
     */
    class WriteCompletionHandler implements 
            CompletionHandler<Integer, ByteBuffer> {
        
        private final AsynchronousSocketChannel socketChannel;
        private final ByteBuffer buffer;
        
        public WriteCompletionHandler(AsynchronousSocketChannel socketChannel, 
                                     ByteBuffer buffer) {
            this.socketChannel = socketChannel;
            this.buffer = buffer;
        }
        
        @Override
        public void completed(Integer result, ByteBuffer attachment) {
            // 数据写入完成后,清空缓冲区并继续读取下一条消息
            buffer.clear();
            socketChannel.read(buffer, buffer, new ReadCompletionHandler(socketChannel));
        }
        
        @Override
        public void failed(Throwable exc, ByteBuffer attachment) {
            System.err.println("写入数据失败:" + exc.getMessage());
            try {
                socketChannel.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

4.4 AIO 优缺点

优点 缺点
真正的异步 I/O,无需轮询 编程复杂度高,回调嵌套容易造成混乱
适合长连接、大文件传输 JDK 对 AIO 的支持不如 NIO 成熟
系统资源利用率高 调试困难,错误处理复杂

五、三种 I/O 模型深度对比

5.1 数据流对比图

flowchart LR subgraph BIO["BIO 流程"] direction TB B1["发起读请求"] --> B2["阻塞等待内核准备数据"] B2 --> B3["阻塞等待内核拷贝数据"] B3 --> B4["处理数据"] end subgraph NIO["NIO 流程"] direction TB N1["发起读请求"] --> N2{"数据是否就绪?"} N2 -- 否 --> N3[立即返回
继续其他任务] N3 --> N4[轮询检查] N4 --> N2 N2 -- 是 --> N5[阻塞等待数据拷贝] N5 --> N6[处理数据] end subgraph AIO[AIO 流程] direction TB A1[发起异步读请求] --> A2[立即返回] A2 --> A3[继续其他任务] A1 --> K[内核准备数据并拷贝] K --> A4[回调通知] A4 --> A5[处理数据] end BIO ~~~ NIO ~~~ AIO

5.2 详细对比表

对比维度 BIO NIO AIO
I/O 模型 同步阻塞 同步非阻塞 异步非阻塞
线程模型 一个连接一个线程 一个线程处理多个连接 回调机制,不占用线程
数据拷贝 应用线程负责 应用线程负责 内核完成,回调通知
编程复杂度 简单 中等 复杂
调试难度 容易 中等 困难
CPU 利用率 低(线程阻塞)
内存占用 高(线程多)
并发能力
吞吐量
响应时间 中等
典型应用 传统 Socket,JDBC Tomcat,Netty,Jetty 文件服务器,专业中间件
Java 版本 JDK 1.0+ JDK 1.4+ JDK 1.7+

5.3 性能对比场景

场景 BIO NIO AIO 推荐方案
连接数 < 1000 较好 BIO(简单)
连接数 1000-10000 NIO
连接数 > 10000 不可用 较好 AIO
短连接、高频请求 优秀 NIO
长连接、低频交互 优秀 AIO
大文件传输 中等 优秀 AIO
实时性要求高 中等 优秀 优秀 NIO/AIO

六、实际应用建议

6.1 技术选型指南

  1. 简单应用,连接数少(<100):

    • 选择 BIO,开发简单,维护容易
    • 示例:小型管理系统、内部工具
  2. 高并发 Web 服务(1000-10000 连接):

    • 选择 NIO,性能好,生态丰富
    • 示例:Web 服务器、API 网关、即时通讯
  3. 大文件传输、长连接

    • 选择 AIO,真正的异步 I/O
    • 示例:文件服务器、视频流媒体
  4. 中间件开发

    • 选择 NIO(如 Netty),稳定性好,社区活跃
    • 示例:RPC 框架、消息队列
  • 大多数场景:选择 NIO(通过 Netty 等框架)
  • 简单场景:BIO 足够
  • 特殊场景(大文件、长连接):考虑 AIO

6.2 常见框架对比

框架 底层 I/O 模型 适用场景
Tomcat NIO(默认)/BIO Web 应用服务器
Netty NIO 高性能网络应用
Jetty NIO 嵌入式 Web 服务器
Undertow NIO 高并发 Web 服务器
Grizzly NIO 通用网络框架

6.3 最佳实践

  1. 避免在 NIO 的 Handler 中做耗时操作,应提交到业务线程池
  2. 合理设置缓冲区大小,避免内存浪费
  3. 处理半包/粘包问题,使用消息定长或分隔符,发送消息的时候先发送数据长度,再发送消息,根据消息长度再获取消息
  4. 做好异常处理,避免资源泄露
  5. 监控线程池和连接数,及时发现问题

相关推荐
小码哥_常2 小时前
告别繁琐try - catch!打造全局异常拦截的魔法城堡
后端
Hoffer_2 小时前
MySQL 强制索引:USE/FORCE INDEX 用法与避坑
后端·mysql
Hoffer_2 小时前
MySQL 索引核心操作:CREATE/DROP/SHOW
后端·mysql
神奇小汤圆2 小时前
拒绝写重复代码,试试这套开源的 SpringBoot 组件,效率翻倍~
后端
哈密瓜的眉毛美2 小时前
零基础学Java|第八篇:面向对象编程的类与对象(基础)
后端
神奇小汤圆2 小时前
架构师手记:彻底终结 Kafka 丢消息与重复消费的“核武器”
后端
明月_清风3 小时前
Python 内存手术刀:sys.getrefcount 与引用计数的生死时速
后端·python
明月_清风3 小时前
Python 消失的内存:为什么 list=[] 是新手最容易踩的“毒苹果”?
后端·python
IT_陈寒17 小时前
Python开发者必知的5大性能陷阱:90%的人都踩过的坑!
前端·人工智能·后端