如何在 Java 中使用 BIO、NIO 和 AIO?

一、BIO 用法(同步阻塞)

特点

  • 一个连接启动一个线程
  • accept()read() 都会阻塞
  • 代码最简单

BIO 服务端

java 复制代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

// BIO 服务端
public class BIOServer {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(9999);
        System.out.println("BIO 服务端已启动,等待连接...");

        while (true) {
            // 阻塞,等待客户端连接
            Socket socket = serverSocket.accept();
            System.out.println("客户端已连接:" + socket);

            // 每来一个客户端,开一个线程
            new Thread(() -> {
                try {
                    BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                    String msg;
                    // 阻塞读取数据
                    while ((msg = br.readLine()) != null) {
                        System.out.println("收到:" + msg);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

BIO 客户端(可开多个测试)

java 复制代码
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Scanner;

public class BIOClient {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1", 9999);
        OutputStreamWriter osw = new OutputStreamWriter(socket.getOutputStream());
        Scanner scanner = new Scanner(System.in);

        while (true) {
            String msg = scanner.next();
            osw.write(msg + "\n");
            osw.flush();
        }
    }
}

二、NIO 用法(同步非阻塞)

重点:三大组件

  • Selector:选择器(一个线程管理多个连接)
  • ServerSocketChannel:服务端通道
  • SocketChannel:客户端通道
  • Buffer:缓冲区

NIO 服务端(一个线程处理所有连接)

java 复制代码
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

// NIO 服务端
public class NIOServer {
    public static void main(String[] args) throws IOException {
        // 1. 创建选择器
        Selector selector = Selector.open();

        // 2. 开启服务端通道
        ServerSocketChannel serverChannel = ServerSocketChannel.open();
        serverChannel.bind(new InetSocketAddress(8888));
        serverChannel.configureBlocking(false); // 非阻塞

        // 3. 注册到选择器,监听连接事件
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("NIO 服务端已启动");

        while (true) {
            // 阻塞等待事件
            selector.select();

            // 遍历事件
            Iterator<SelectionKey> it = selector.selectedKeys().iterator();
            while (it.hasNext()) {
                SelectionKey key = it.next();
                it.remove();

                if (key.isAcceptable()) {
                    // 有新连接
                    SocketChannel channel = serverChannel.accept();
                    channel.configureBlocking(false);
                    channel.register(selector, SelectionKey.OP_READ);
                } else if (key.isReadable()) {
                    // 有数据可读
                    SocketChannel channel = (SocketChannel) key.channel();
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    channel.read(buffer);
                    String msg = new String(buffer.array()).trim();
                    System.out.println("收到:" + msg);
                }
            }
        }
    }
}

三、AIO 用法(异步非阻塞)

特点

  • 真正异步
  • 基于回调
  • 操作系统完成后通知
  • Windows 支持好,Linux 一般

AIO 服务端

java 复制代码
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.net.InetSocketAddress;

// AIO 服务端
public class AIOServer {
    public static void main(String[] args) throws Exception {
        AsynchronousServerSocketChannel serverChannel = AsynchronousServerSocketChannel.open();
        serverChannel.bind(new InetSocketAddress(7777));
        System.out.println("AIO 服务端已启动");

        // 异步接受连接,回调处理
        serverChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Object>() {
            @Override
            public void completed(AsynchronousSocketChannel client, Object attachment) {
                // 继续接收下一个连接
                serverChannel.accept(null, this);

                // 异步读取
                ByteBuffer buffer = ByteBuffer.allocate(1024);
                client.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
                    @Override
                    public void completed(Integer result, ByteBuffer buffer) {
                        buffer.flip();
                        String msg = new String(buffer.array(), 0, result);
                        System.out.println("收到:" + msg);
                    }

                    @Override
                    public void failed(Throwable exc, ByteBuffer buffer) {}
                });
            }

            @Override
            public void failed(Throwable exc, Object attachment) {}
        });

        Thread.sleep(Integer.MAX_VALUE); // 保持服务端运行
    }
}

四、三者用法核心区别(一眼看懂)

方式 阻塞 线程模型 核心API 代码风格
BIO 阻塞 1连接1线程 ServerSocket 简单IO流
NIO 非阻塞 1线程管理N连接 Selector/Channel 通道+缓冲区+选择器
AIO 异步非阻塞 操作系统回调 AsynchronousChannel 回调函数

五、企业真实使用场景

  1. BIO:基本不用,并发太低
  2. NIONetty 框架(Dubbo、RocketMQ、SkyWalking、网关全用它)
  3. AIO:几乎不用,Linux 支持差

99% 高性能网络编程 = Netty(NIO)


总结

  • BIO:流 + 阻塞 + 多线程
  • NIO:通道 + 缓冲区 + 选择器(最常用)
  • AIO:异步 + 回调
相关推荐
hyunbar1 小时前
NOT IN 的 NULL 陷阱:一次 UNION 数据“神秘消失“
开发语言·sql
Kurisu5751 小时前
深度拆解:从令牌桶到滑动窗口,高并发系统限流算法的数学本质与边界
java·网络·算法
189228048611 小时前
NV022固态MT29F16T08GWLCEM5-QBES:C
c语言·开发语言
repetitiononeoneday1 小时前
【面试题】Redis缓存穿透如何解决?
java·redis·缓存
Solis程序员2 小时前
亿级流量设计之布隆过滤器原理、优缺点及主流替代方案
java
划水的code搬运工小李2 小时前
下载CSDN到PDF
开发语言·pdf·swift
不负岁月无痕2 小时前
STL-- C++ stack_queue _priority_queue类 模拟实现
开发语言·c++
半个烧饼不加肉2 小时前
JS 底层探究--上下文
开发语言·javascript·ecmascript