java nio 的多路复用是通过 selector 对象实现的,它允许单个线程监控多个 channel 的状态变化。开发者只需将感兴趣的通道注册到选择器上,并调用 select() 方法阻塞等待,当有通道就绪时,系统会返回对应的 selectionkey 集合,从而让线程能高效地处理并发 i/o 操作而无需为每个连接创建独立线程。

如何注册通道并监听特定事件
要实现多路复用,首先需要创建一个 Selector 实例,然后将非阻塞模式的 ServerSocketChannel 或 SocketChannel 注册到该选择器上。在注册过程中,必须指定感兴趣的事件类型,如 OP_ACCEPT、OP_READ 或 OP_WRITE,这样选择器才能知道何时唤醒线程进行处理。

import java.nio.channels.*;
import java.io.IOException;
public class SimpleSelector {
public static void main(String[] args) throws IOException {
Selector selector = Selector.open();
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
serverChannel.bind(new java.net.InetSocketAddress(8080));
// 注册 OP_ACCEPT 事件
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("Server started on port 8080");
while (true) {
int readyChannels = selector.select();
if (readyChannels == 0) continue;
for (SelectionKey key : selector.selectedKeys()) {
if (key.isAcceptable()) {
// 处理新连接
}
key.selector().selectedKeys().remove(key);
}
}
}
}
select() 方法是如何筛选就绪通道的
select() 方法是多路复用的核心,它会阻塞直到至少有一个注册的通道满足其感兴趣的条件。当通道状态改变(如数据到达或连接建立)时,操作系统内核会将该通道标记为就绪,select() 返回后,通过 selectedKeys() 获取这些就绪键。开发者需要遍历这个集合,并根据 SelectionKey 的类型执行相应的读写逻辑,处理完后务必从集合中移除当前键以避免重复处理。

import java.nio.channels.*;
import java.util.Set;
import java.util.Iterator;
public class SelectLoop {
public static void process(Selector selector) throws IOException {
Set<selectionkey> selectedKeys = selector.selectedKeys();
Iterator<selectionkey> it = selectedKeys.iterator();
while (it.hasNext()) {
SelectionKey key = it.next();
try {
if (key.isReadable()) {
// 执行读取逻辑
} else if (key.isWritable()) {
// 执行写入逻辑
}
} catch (Exception e) {
key.cancel();
}
it.remove(); // 必须移除已处理的键
}
}
}</selectionkey></selectionkey>
如果通道在 select 期间关闭会发生什么
如果在 select() 等待期间,某个通道被关闭或发生异常,该通道的 SelectionKey 会自动被取消。此时 select() 方法会立即返回,且返回值大于零,表示有就绪事件。在随后的 selectedKeys() 迭代中,开发者可以通过检查 key.isValid() 来过滤掉无效的键,或者捕获 CancellationException。如果不主动取消或忽略这些无效键,它们会一直留在 selectedKeys 集合中,导致每次循环都重复处理同一个错误状态,引发资源浪费或逻辑错误。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











