在本课中,我们将熟悉Selector类。此类位于java.nio.channels包中,因此您无需下载或配置任何内容即可使用它。选择对象可以监视一个或多个通道对象,检查它们是否准备好读/写等。最重要的是,选择器需要一个流,而不是每个通道一个流。

我们使用静态打开方法创建选择器:


Selector selector = Selector.open();

之后,可以在选择器对象中注册通道:


SelectionKey key1 = channel1.register(selector, SelectionKey.OP_READ);
SelectionKey key2 = channel2.register(selector, SelectionKey.OP_WRITE);

register方法的第二个参数确定选择器将监视哪个操作。如果需要同时监控多个操作,可以使用按位或:


SelectionKey.OP_READ | SelectionKey.OP_WRITE

当任何通道上发生 I/O 操作时,选择器都会通知我们。例如,您可以通过这种方式从大量数据源中读取数据。

这里我们需要提到的是,通道必须处于非阻塞模式才能与选择器一起使用:


channel1.configureBlocking(false);
channel2.configureBlocking(false);
SelectionKey key1 = channel1.register(selector, SelectionKey.OP_READ);
SelectionKey key2 = channel2.register(selector, SelectionKey.OP_WRITE);

因此选择器不能与FileChannel一起工作,因为FileChannel不能切换到非阻塞模式(configureBlocking方法在SelectableChannel类中声明,FileChannel不继承)。

从图中可以看出,选择器适合与套接字一起使用。我们将在第二个模块结束时与他们合作。

选择键

使用选择器注册频道时,我们会得到一个选择键目的。该对象包含有关频道注册的数据。

您可以使用 key 来确定通道是否准备好接受某个值:


key.isReadable()
key.isAcceptable()
key.isConnectable()
key.isWritable()

key可以给你对应的channel和selector:


Channel channel = key.channel();
Selector selector = key.selector();

您可以将任何对象附加到密钥,以便将来跟踪它。这可以在频道注册期间(通过第三个参数)或之后完成:

  1. SelectionKey key = channel.register(selector, SelectionKey.OP_ACCEPT, object);

  2. 键.附加(对象);

稍后,您可以从键中获取附加对象:


Object object = key.attachment();

结论

使用选择器注册频道后,我们可以:

  • 找出准备执行指定操作的通道数
  • 阻止我们程序的执行,直到至少一个通道准备就绪
  • 为就绪频道获取一组密钥
  • 和更多

在第二个模块的末尾,我们将在实践中试用选择器。