java nio中selector.select()有三种形式:select()无限阻塞直至就绪或唤醒;select(long timeout)最多阻塞指定毫秒;selectnow()立即返回,完全非阻塞;均需处理selectedkeys()并支持wakeup()唤醒。

Java NIO 中 Selector.select() 方法本身是阻塞的,但可通过不同重载形式实现阻塞等待、带超时的阻塞等待,或非阻塞轮询。关键在于理解三种 select 方法的行为差异及唤醒机制。
select():无限期阻塞,直到有就绪通道或被唤醒
调用 selector.select() 会一直阻塞,直到至少一个注册的 Channel 出现就绪事件(如可读、可写),或者当前线程被其他线程通过 selector.wakeup() 显式唤醒。
- 适合需要“有事才干活”的场景,例如典型的服务端事件循环
- 若没有 Channel 就绪且无人唤醒,线程将一直挂起,不消耗 CPU
- 每次返回后需遍历
selectedKeys()处理就绪事件,并注意清除已处理的 key(调用iterator.remove())
select(long timeout):阻塞最多指定毫秒数,超时后自动返回
selector.select(timeout) 会在有就绪事件、被唤醒、或等待时间超过 timeout 毫秒三者之一发生时返回。
-
timeout = 0等价于select()(无限阻塞) -
timeout > 0表示最多等待该毫秒数;超时后即使无就绪事件也返回,此时selectedKeys().size()可能为 0 - 常用于需要定期执行维护任务(如清理缓存、检查心跳)的事件循环中
selectNow():完全非阻塞,立即返回当前就绪状态
selector.selectNow() 不阻塞,立刻检查并返回当前已就绪的 Channel 数量(可能为 0)。
- 适合嵌入在繁忙循环中做快速轮询,但频繁调用会浪费 CPU
- 一般不单独用于主事件循环,多配合定时器或其它调度逻辑使用
- 返回后仍需正常处理
selectedKeys(),逻辑与前两者一致
唤醒与中断控制:主动打破阻塞的关键手段
阻塞中的 select() 或 select(timeout) 可被外部线程用 selector.wakeup() 打断,立即返回(即使未超时、也无就绪事件)。
-
wakeup()是线程安全的,多次调用等效于一次(内部使用 volatile 标志位) - 如果 select 正在阻塞,
wakeup()会让它立刻退出;如果 select 已返回或未开始,该次唤醒会被“记住”,下次 select 调用会立即返回 - 也可通过中断线程(
thread.interrupt())触发ClosedByInterruptException,但需确保 selector 未关闭且线程处于可中断状态
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











