`

【Java NIO 简例】Selector

    博客分类:
  • Java
nio 
阅读更多

原文:《Java NIO Selector

Selector 可以检查多个 Channel 实例,发现那些已经就绪,可以读/写的 Channel。
通过这个机制,可以实现 单线程处理多个Channel,从而处理多个网络连接

 

为什么要使用 Selector ?

对操作系统来说,线程之间的切换代价较高,而且每个线程都会占用一些内存资源。所以线程越少越好。
而利用Select可以实现只用一个线程处理多个 Channel。

现代操作系统和CPU在多任务处理方面越来越强,多线程开销也更小了。事实上,对于一个多核CPU,如果不采用多任务,可能就是在浪费CPU的算力。但这些属于另一个话题范畴。


 

创建 Selector

Selector selector = Selector.open();

 

将 Channel 注册到 Selector

channel.configureBlocking(false);
SelectionKey key = channel.register(selector, SelectionKey.OP_READ);
  • 此处的 Channel 必须设置为 非阻塞 模式。
    FileChannel 没有非阻塞模式,所以它不能与 Selector 共用;SocketChannel 有非阻塞模式,所以它可以。
  • SelectionKey.OP_READ 表示需要监听 Channel 的 Read 事件。
    即,当 Channel 可以被读取时,Selector 会将 OP_READ 加入相应 SelectionKey 的 “已就绪操作集合”中,并把该 SelectionKey 加入 Selector 的 selected-key 集合,供后续操作使用。
Channel 事件及对应的常量值 Channel 事件 常量值 含义
Connect SelectionKey.OP_CONNECT  完成与远程服务器的连接(或连接出错)
Accept SelectionKey.OP_ACCEPT 连接被接受(或出错) 
Read SelectionKey.OP_READ

“读操作”准备就绪

或 已读到数据流的末尾

或 Channel 被连接的另一端关闭

或 出错

Write SelectionKey.OP_WRITE

“写操作” 准备就绪

或 Channel 被连接的另一端关闭

或 出错

 

如果需要监听多个事件,可以用“或”操作连接相应的常量值。如:

int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE;

 

SelectionKey

SelectionKey 包含的信息主要有:

  • 监听事件类型集合(Interest Set)
  • 已就绪事件类型集合(Ready Set)
  • Channel
  • Selector
  • 附带的对象(可选)

Interest Set

可通过 SelectionKey.interetOps() 获取该集合,并通过“位操作”来判断是否注册监听了某个事件。

int interestSet = selectionKey.interestOps();

boolean isInterestedInConnect = interestSet & SelectionKey.OP_CONNECT;
boolean isInterestedInAccept = interestSet & SelectionKey.OP_ACCEPT;
boolean isInterestedInRead = interestSet & SelectionKey.OP_READ;
boolean isInterestedInWrite = interestSet & SelectionKey.OP_WRITE;

 

Ready Set

可通过 SelectionKey.readyOps() 获取该集合。
可以像 Interest Set 那样通过“位操作”来判断某个事件是否已发生。
也可以直接调用 SelectionKey 对象相应的方法来判断(内部原理相同)。

int readySet = selectionKey.readyOps();

selectionKey.isConnectable();
selectionKey.isAcceptable();
selectionKey.isReadable();
selectionKey.isWritable();

 

Channel 和 Selector

可通过 SelectionKey 对象相关的方法来获取其对应的 Channel 和 Selector

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

 

附带对象

可将某个对象附带到 SelectionKey 对象上,为后续处理数据提供方便。如,把处理 Channel 数据的 Buffer 对象附带到key上。

selectionKey.attach(obj);
Object attachedObj = selectionKey.attachment();

// 也可在注册Selector时指定附带对象
SelectionKey key = channel.register(selector, SelectionKey.OP_READ, obj);

 

从 Selector 获取就绪的 Channel

可通过 Selector 对象的以下3个方法之一得知是否有 Channel 已就绪。这三个方法都会返回 int,表示已就绪 Channel 的数量

  • select() 阻塞,直到至少有一个 Channel 就绪
  • select(long timeout) 阻塞,直到至少有一个 Channel 就绪 或 超时
  • selectNow() 非阻塞。无论当前有没有 Channel 就绪,都会立即返回

selectedKeys()

如果上述select方法返回的值大于0,即,有Channel就绪,就可以通过 selector 对象的 selectedKeys() 方法获取这些 Channel 对应的 SelectionKey。再通过 SelectionKey 实例获取 Channel 实例并执行后续操作。

Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while (keyIterator.hasNext()) {
  SelectionKey key = keyIterator.next();
  // 处理Channel
  keyIterator.remove();
}

 

Selector.wakeup()

如果一个线程调用了 Selector.select() 方法并发生阻塞,此时另一个线程调用了该 Selector 对象的 wakeup() 方法,则前一个被阻塞的线程将会立即返回。

如果调用 wakeup() 时,没有线程阻塞在 select() 方法,则下一个调用 select() 方法的线程将立即返回。除非期间调用了 selectNow() 方法

 

Selector.close()

如果调用了 Selector 对象的 close() 方法,则 Selector 对象会被关闭,其中的 SelectionKey 实例将失效,但 Channel 不会被关闭

 

完整的 Selector 示例

Selector selector = Selector.open();
channel.configureBlocking(false);
SelectionKey key = channel.register(selector, SelectionKey.OP_READ);
while (true) {
  int readyChannelCount = selector.selectNow();
  if (0 == readyChannelCount) {
    continue;
  }

  Set selectedKeys = selector.selectedKeys();
  Iterator keyIterator = selectedKeys.iterator();
  while(keyIterator.hasNext()) {
    SelectionKey key = keyIterator.next();

    if(key.isAcceptable()){
      // 连接已被一个 ServerSocketChannel 接受
    } else if (key.isConnectable()) {
      // 已与远程服务器建立连接
    } else if (key.isReadable()) {
      // “读操作”已准备就绪
    } else if (key.isWritable()) {
      // “写操作”已准备就绪
    }

    keyIterator.remove();
  }
}
  • 大小: 12.6 KB
分享到:
评论

相关推荐

    Java NIO——Selector机制解析三(源码分析)

    本文将深入探讨Java NIO中的Selector机制,并通过源码分析来理解其实现原理。 Selector机制是Java NIO中的核心组件,它允许单线程同时监控多个通道(Channels)的状态变化,例如连接就绪、数据可读或可写等。这种...

    Java_NIO-Selector.rar_java nio_selector

    Selector是Java NIO框架中的核心组件,它使得单个线程能够管理多个通道(Channels),从而提高系统资源利用率并优化性能。下面我们将详细探讨Java NIO中的Selector机制。 1. **Selector的作用** Selector的主要功能...

    Java Nio selector例程

    java侧起server(NioUdpServer1.java),基于Java Nio的selector 阻塞等候,一个android app(NioUdpClient1文件夹)和一个java程序(UI.java)作为两个client分别向该server发数据,server收到后分别打印收到的消息...

    Java_NIO类库Selector机制解析.doc

    Java_NIO类库Selector机制解析.docJava_NIO类库Selector机制解析.docJava_NIO类库Selector机制解析.docJava_NIO类库Selector机制解析.doc

    JavaNIO库Selector机制解析.docx

    JavaNIO库Selector机制解析.docx

    java nio Selector的使用-客户端

    Selector是Java NIO中的核心组件之一,它允许单个线程处理多个通道(channels)的读写事件,极大地提高了服务器的并发能力。本篇文章将深入探讨如何在Java NIO中使用Selector处理客户端的I/O请求。 首先,我们需要...

    Java NIO实战开发多人聊天室

    01-Java NIO-课程简介.mp4 05-Java NIO-Channel-FileChannel详解(一).mp4 06-Java NIO-Channel-FileChannel详解(二).mp4 08-Java NIO-Channel-...23-Java NIO-Selector-示例代码(客户端).mp4 24

    JavaNIO chm帮助文档

    Java NIO系列教程(六) Selector Java NIO系列教程(七) FileChannel Java NIO系列教程(八) SocketChannel Java NIO系列教程(九) ServerSocketChannel Java NIO系列教程(十) Java NIO DatagramChannel Java ...

    Java-NIO类库Selector机制解析.docx

    "Java NIO Selector 机制解析" Java NIO(New I/O)类库是Java 1.4版本以后引入的新一代I/O机制,相比传统的I/O机制,NIO提供了高效、异步、多路复用的I/O操作模式。Selector机制是NIO类库中的一种核心机制,用于...

    java NIO和java并发编程的书籍

    java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java NIO和java并发编程的书籍java...

    Java NIO英文高清原版

    Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java平台中用于替代标准I/O(BIO)模型的一种新机制。NIO在Java 1.4版本引入,提供了更高效的数据处理和通道通信方式,特别适用于高并发、大数据...

    java NIO.zip

    Java NIO,全称为Non-Blocking Input/Output(非阻塞输入/输出),是Java标准库提供的一种替代传统的I/O模型的新技术。自Java 1.4版本引入NIO后,它为Java开发者提供了更高效的数据传输方式,尤其是在处理大量并发...

    java NIO技巧及原理

    通过Selector,Java NIO可以同时监听多个通道的事件。当某个通道有数据可读或可写时,Selector会通知用户程序,避免了为每个连接创建单独线程的开销。 **NIO框架分析:** 在实际开发中,我们通常会使用一些NIO框架...

    Java NIO Socket基本

    `java.nio.Selector`是选择器的主要接口。 4. **管道(Pipe)**:在某些特定情况下,两个线程之间可以使用`java.nio.Pipe`进行单向数据传递。 5. **文件系统API**:NIO还提供了`java.nio.file`包,包含一系列与...

    java nio 包读取超大数据文件

    ### Java NIO 处理超大数据文件的知识点详解 #### 一、Java NIO简介 Java NIO(New IO)是Java平台上的新输入/输出流API,它提供了与传统IO(即Java IO)不同的数据处理方式。NIO在Java 1.4版本引入,并在后续版本...

    Java NIO 中文 Java NIO 中文 Java NIO 中文文档

    Java NIO 深入探讨了 1.4 版的 I/O 新特性,并告诉您如何使用这些特性来极大地提升您所写的 Java 代码的执行效率。这本小册子就程序员所面临的有代表性的 I/O 问题作了详尽阐述,并讲解了 如何才能充分利用新的 I/O ...

    java NIO 视频教程

    Java NIO(New IO)是一个可以替代标准Java IO API的IO API(从Java 1.4开始),Java NIO提供了与标准IO不同的IO工作方式。 Java NIO: Channels and Buffers(通道和缓冲区) 标准的IO基于字节流和字符流进行操作的,...

    java NIO实例

    在`NIOServer.java`中,服务器端首先会初始化Selector并注册ServerSocketChannel,之后进入一个无限循环,调用selector.select()方法等待事件发生。当有客户端连接时,服务器会处理新连接,创建SocketChannel,并将...

    深入了解java NIO之Selector(选择器)

    "深入了解 Java NIO 之 Selector(选择器)" Java NIO(Non-Blocking I/O)中,Selector(选择器)是一种重要的组件,它提供了选择执行已经就绪的任务的能力,使得多元 I/O 成为可能。在 Java 中,Selector 是一种...

Global site tag (gtag.js) - Google Analytics