java nio 中的非阻塞 io 和异步 io 核心区别在于操作模式:非阻塞 io(nio)是同步的,需要应用层主动通过 selector 轮询事件并手动读写数据;而异步 io(aio)是真正的异步,由操作系统在 i/o 完成后回调通知应用层,应用无需轮询。简单来说,nio 是你去柜台排队问进度,aio 是柜台办完事打电话通知你。

NIO 非阻塞模式下 Selector 如何分发 Channel 事件
在非阻塞 IO 中,程序必须显式调用 Selector.select() 来等待就绪事件,并通过迭代 selectedKeys() 集合来处理具体的 Readable 或 Writable 事件。这意味着 CPU 需要不断参与 I/O 状态的检查,或者在空闲时阻塞等待,但一旦有事件发生,业务逻辑必须由开发者编写的代码执行读写操作。

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;
import java.util.Set;
public class NioServer {
public static void main(String[] args) throws IOException {
Selector selector = Selector.open();
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
serverChannel.bind(new InetSocketAddress(8080));
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
selector.select(); // 阻塞直到有事件
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> it = keys.iterator();
while (it.hasNext()) {
SelectionKey key = it.next();
if (key.isAcceptable()) {
SocketChannel client = serverChannel.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
client.read(buffer); // 手动读取数据
}
it.remove();
}
}
}
}AIO 异步模式下 CompletionHandler 如何处理结果
在异步 IO(AIO)中,程序发起 I/O 请求后立即返回,不阻塞也不轮询。当操作系统完成 I/O 操作后,会自动触发注册的 CompletionHandler 回调方法。开发者只需关注 completed 和 failed 两个状态,并在其中处理数据,CPU 在等待期间可以完全释放去处理其他任务。
立即学习“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;
public class AiOServer {
public static void main(String[] args) throws IOException {
AsynchronousServerSocketChannel server = AsynchronousServerSocketChannel.open();
server.bind(new InetSocketAddress(8080));
server.accept(null, new CompletionHandler<AsynchronousSocketChannel, Object>() {
@Override
public void completed(AsynchronousSocketChannel result, Object attachment) {
server.accept(null, this); // 继续接受下一个连接
ByteBuffer buffer = ByteBuffer.allocate(1024);
result.read(buffer, buffer, new CompletionHandler<Integer, ByteBuffer>() {
@Override
public void completed(Integer resultSize, ByteBuffer buffer) {
buffer.flip();
System.out.println(new String(buffer.array(), 0, resultSize));
buffer.clear();
}
@Override
public void failed(Throwable exc, ByteBuffer attachment) {
exc.printStackTrace();
}
});
}
@Override
public void failed(Throwable exc, Object attachment) {
exc.printStackTrace();
}
});
Thread.sleep(Long.MAX_VALUE); // 保持主线程运行
}
}当 AIO 回调中 read 返回 0 字节时代表什么含义
在 AIO 的 read 操作中,如果 CompletionHandler.completed 方法的第一个参数 resultSize 为 0,这通常表示对端已经关闭了连接(EOF),而不是没有数据可读。这与 NIO 中 read 返回 -1 的含义一致,开发者应当据此判断连接生命周期结束并进行资源清理。


















