Java NIO(New I/O)中的 Selector 是一个关键组件,用于实现非阻塞 I/O 操作。它允许一个线程同时监视多个通道(Channel)上的事件,比如连接请求、数据到达等。通过使用 Selector,可以提高应用程序的性能和资源利用率,尤其是在处理大量并发连接时。
Selector 的基本概念
-
非阻塞 I/O:Java NIO 支持非阻塞模式,允许通道在没有可用数据时立即返回,而不是阻塞线程。这使得一个线程可以管理多个连接。
-
通道(Channel):NIO 的核心概念之一,代表一个能够执行 I/O 操作的对象,如
SocketChannel、ServerSocketChannel等。 -
选择器(Selector):用于监视多个通道的 I/O事件。通过
Selector,一个线程可以高效地管理多个通道。 -
选择键(SelectionKey):表示注册在
Selector上的通道及其感兴趣的事件。每个通道在Selector上注册后,会生成一个SelectionKey。
Selector 的主要方法
-
open():
Selector selector = Selector.open();创建一个新的
Selector实例。 -
register():
SelectionKey key = channel.register(selector, SelectionKey.OP_READ);将通道注册到
Selector上,并指定感兴趣的事件(如OP_READ、OP_WRITE、OP_CONNECT、OP_ACCEPT)。 -
select():
int readyChannels = selector.select();阻塞直到至少有一个通道准备好进行 I/O 操作。
-
selectNow():
int readyChannels = selector.selectNow();非阻塞版本的
select(),立即返回可用的通道数。 -
select(long timeout):
int readyChannels = selector.select(1000);带超时的
select()方法,阻塞到有通道准备好或超时。 -
selectedKeys():
Set<SelectionKey> selectedKeys = selector.selectedKeys();返回一组
SelectionKey,代表已准备好的通道。 -
wakeup():
selector.wakeup();使阻塞在
select()方法上的线程立即返回。 -
close():
selector.close();关闭
Selector,释放资源。
使用 Selector 的基本步骤
-
打开 Selector:
Selector selector = Selector.open(); -
打开并配置通道:
ServerSocketChannel serverChannel = ServerSocketChannel.open(); serverChannel.bind(new InetSocketAddress(port)); serverChannel.configureBlocking(false); -
将通道注册到 Selector:
serverChannel.register(selector, SelectionKey.OP_ACCEPT); -
循环等待事件:
while (true) { int readyChannels = selector.select(); if (readyChannels == 0) continue; Set<SelectionKey> selectedKeys = selector.selectedKeys(); Iterator<SelectionKey> keyIterator = selectedKeys.iterator(); while (keyIterator.hasNext()) { SelectionKey key = keyIterator.next(); if (key.isAcceptable()) { // 处理接受事件 } else if (key.isReadable()) { // 处理读取事件 } else if (key.isWritable()) { // 处理写入事件 } else if (key.isConnectable()) { // 处理连接事件 } keyIterator.remove(); } }
注意事项
- 线程安全性:
Selector不是线程安全的,通常一个Selector由一个线程管理。 - 资源管理:确保在不使用时关闭通道和选择器,以释放资源。
- 事件处理:处理完每个
SelectionKey后,需要从selectedKeys集合中移除,以避免重复处理。
使用 Selector 可以有效地管理多个网络连接,尤其适用于需要处理大量并发连接的服务器应用程序。
参考:
NIO SelectionKey 详解
我们在看 xxljob 源码时 ,就有哟过netty 做http服务器的代码