Java NIO 中的 Selector(选择器) 用于实现 多路复用 IO,可以用一个线程管理多个 Channel(如 SocketChannel、ServerSocketChannel),非常适合写高性能网络服务器。
下面从 概念 → 使用步骤 → 完整示例 给你讲清楚。
OP_ACCEPT:服务端接收连接OP_CONNECT:客户端连接完成OP_READ:可读OP_WRITE:可写channel.configureBlocking(false);
Selector selector = Selector.open();
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.bind(new InetSocketAddress(8080));
serverChannel.configureBlocking(false);
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
int readyChannels = selector.select(); // 阻塞等待事件
if (readyChannels == 0) continue;
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> it = keys.iterator();
while (it.hasNext()) {
SelectionKey key = it.next();
it.remove(); // 必须移除
if (key.isAcceptable()) {
// 有连接进来
}
if (key.isReadable()) {
// 有数据可读
}
}
}
public class NioServer {
public static void main(String[] args) throws Exception {
Selector selector = Selector.open();
ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.bind(new InetSocketAddress(8080));
serverChannel.configureBlocking(false);
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("Server started...");
while (true) {
selector.select();
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey key = it.next();
it.remove();
if (key.isAcceptable()) {
ServerSocketChannel server =
(ServerSocketChannel) key.channel();
SocketChannel client = server.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);
System.out.println("Client connected");
} else if (key.isReadable()) {
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
int len = client.read(buffer);
if (len > 0) {
buffer.flip();
System.out.println("Received: " +
new String(buffer.array(), 0, len));
client.write(buffer);
} else if (len == -1) {
client.close();
}
}
}
}
}
}
SocketChannel channel = SocketChannel.open();
channel.configureBlocking(false);
channel.connect(new InetSocketAddress("localhost", 8080));
Selector selector = Selector.open();
channel.register(selector, SelectionKey.OP_CONNECT);
it.remove()select() 会阻塞,selectNow() 不阻塞OP_WRITE)一般不要一直注册,避免 CPU 空转channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
✅ 高并发网络服务
✅ 单线程处理大量连接
❌ 简单程序、少量连接(用 BIO 更简单)
如果你愿意,我可以:
你想看哪个?
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。