java中selector监控连接事件需将socketchannel设为非阻塞并注册op_connect;select返回后调用finishconnect()判断成败,成功则重置interestops为op_read/op_write,失败则关闭通道;须及时cancel key并移除selectedkeys。

Java 中使用 Selector 监控多个通道的连接事件,核心是基于 NIO 的非阻塞 I/O 模型,通过一个线程轮询多个 Channel 的就绪状态,避免为每个连接单独开线程。关键在于正确配置通道为非阻塞模式、注册到选择器并监听 SelectionKey.OP_CONNECT 事件。
创建并初始化 Selector 和非阻塞 SocketChannel
客户端连接远程服务时,需先创建 SocketChannel,设为非阻塞,并调用 connect() —— 此时若未立即连通(如网络延迟),方法返回 false,但连接仍在后台进行。此时必须将该通道注册到 Selector,并关注 OP_CONNECT 事件:
-
必须调用
configureBlocking(false),否则注册会抛IllegalBlockingModeException - 注册时传入
SelectionKey.OP_CONNECT,表示关心“连接是否完成” - 连接成功后,
isConnectionPending()为true,且finishConnect()返回true
在 select 循环中检测 OP_CONNECT 就绪
启动一个 while(true) 循环,调用 selector.select() 阻塞等待事件;有事件就绪后,遍历 selectedKeys(),对每个 SelectionKey 判断其 isConnectable():
- 若为
true,说明连接已建立或失败,需调用channel.finishConnect() - 若返回
true,表示连接成功,可切换为读/写事件(如注册OP_READ) - 若返回
false,说明连接被拒绝或超时,应关闭通道并取消键 - 处理完务必调用
key.cancel()或key.attach(...)管理后续逻辑
注意连接完成后的事件重注册
连接成功只是起点,不能继续监听 OP_CONNECT —— 它只是一次性事件。后续要收发数据,需重新设置关注集:
- 调用
key.interestOps(SelectionKey.OP_READ)替换原操作集 - 也可用
key.interestOps(key.interestOps() | OP_READ)追加(但通常连接后只读或读写) - 如果连接后还要发数据,可立即写入(非阻塞下可能只写部分),再注册
OP_WRITE等可写事件
常见陷阱与建议
实际使用中容易忽略几个细节:
- 不要在
connect()后立刻finishConnect(),必须等select()返回且isConnectable()为真 -
OP_CONNECT在连接失败时也会就绪(如目标端口无服务),需检查finishConnect()返回值和异常 - 每次处理完一个 key 后,必须从
selectedKeys()集合中移除(iterator.remove()),否则下次循环还会触发 - 连接过程中发生异常(如
IOException),应关闭通道、取消 key 并清理资源
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











