面试题答案
一键面试多路复用机制实现原理
Selector 基于事件驱动机制,通过一个线程管理多个 Channel 上的 I/O 事件。它不断轮询注册在其上的 Channel,一旦某个 Channel 有感兴趣的事件(如可读、可写等)发生,Selector 就能感知到,并将对应的 SelectionKey 加入到已选择键集合中,从而让应用程序能对这些就绪的 Channel 进行相应的 I/O 操作,达到在一个线程内处理多个 Channel 的目的,提高了资源利用率和程序的并发性能。
关键组件
- Selector:多路复用器,用于监控多个 Channel 上的 I/O 事件。一个 Selector 可以注册多个 Channel。
- Channel:通道,用于在 Java NIO 中进行数据的读写操作,如 SocketChannel、ServerSocketChannel 等。它需要注册到 Selector 上,并指定感兴趣的事件(如读、写、连接等)。
- SelectionKey:当 Channel 注册到 Selector 时,会生成一个 SelectionKey。它代表了 Channel 和 Selector 之间的注册关系,包含了 Channel、Selector 以及该 Channel 感兴趣的事件集合和已经就绪的事件集合等信息。
操作步骤
- 创建 Selector:通过
Selector.open()
方法创建一个 Selector 实例。 - 创建并配置 Channel:例如创建
SocketChannel
或ServerSocketChannel
,并设置为非阻塞模式(channel.configureBlocking(false)
),因为 NIO 多路复用机制基于非阻塞 I/O。 - 注册 Channel 到 Selector:调用
channel.register(selector, SelectionKey.OP_READ)
等方法将 Channel 注册到 Selector 上,并指定感兴趣的事件,这里以注册读事件为例。注册后会返回一个SelectionKey
。 - Selector 轮询事件:调用
selector.select()
方法,该方法会阻塞,直到有注册的 Channel 上有感兴趣的事件发生。select()
方法返回值为发生事件的 Channel 的数量。 - 处理事件:通过
selector.selectedKeys()
获取已选择键集合,遍历这个集合,从每个SelectionKey
中获取对应的Channel
,根据SelectionKey
中就绪的事件类型进行相应的 I/O 操作,如读数据、写数据等。处理完事件后,要记得从已选择键集合中移除当前处理的SelectionKey
,防止重复处理。