`
zachary.guo
  • 浏览: 482804 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

NIO - 选择器基础

    博客分类:
  • NIO
阅读更多
    ◇ 选择器、可选择通道和选择键类
        实际上,与选择器相关的类的 api 有三个,它们用于执行就绪选择:

  • 选择器(Selector):选择器类管理着一个被注册的通道集合的信息和它们的就绪状态。通道是和选择器一起被注册的,并且使用选择器来更新通道的就绪状态。
  •        
  • 可选择通道(SelectableChannel):它是所有支持就绪检查的通道类的父类。FileChannel 对象不是可选择的,因为它没有继承 SelectableChannel。所有 socket 通道都是可选择的,包括从管道(Pipe)对象的中获得的通道。只有 SelectableChannel 可以被注册到 Selector 对象上。一个通道可以被注册到多个选择器上,但对每个选择器而言只能被注册一次。
  •        
  • 选择键(SelectionKey):选择键封装了特定的通道与特定的选择器的注册关系。选择键对象被 SelectableChannel.register() 返回并提供一个表示这种注册关系的标记。选择键包含了两个比特集(以整数的形式进行编码),指示了该注册关系所关心的通道操作,以及通道已经准备好的操作。
SelectableChannel 的相关API方法:
public abstract class SelectableChannel extends AbstractChannel implements Channel {
    // This is a partial API listing
    public abstract SelectionKey register(Selector sel, int ops)
        throws ClosedChannelException;
    public abstract SelectionKey register(Selector sel, int ops, Object att)
        throws ClosedChannelException;
    public abstract boolean isRegistered();
    public abstract SelectionKey keyFor(Selector sel);
    public abstract int validOps();
    public abstract void configureBlocking(boolean block) throws IOException;
    public abstract boolean isBlocking();
    public abstract Object blockingLock();
}

        调用 SelectableChannel 的 register() 方法会将它注册到一个选择器上。如果你试图注册一个处于阻塞状态的通道,register() 将抛出未检查的 IllegalBlockingModeException 异常。此外,通道一旦被注册,就不能回到阻塞状态。试图这么做的话,将在调用 configureBlocking() 方法时将抛出 IllegalBlockingModeException 异常。并且,理所当然地,试图注册一个已经关闭的 SelectableChannel 实例的话,也将抛出 ClosedChannelException 异常,就像方法原型指示的那样。通道在被注册到一个选择器上之前,必须先设置为非阻塞模式(通过调用configureBlocking(false))。

Selector 的相关 API 方法:
public abstract class Selector {
    public static Selector open() throws IOException
    public abstract boolean isOpen();
    public abstract void close() throws IOException;
    public abstract SelectionProvider provider();
    public abstract int select() throws IOException;
    public abstract int select(long timeout) throws IOException;
    public abstract int selectNow() throws IOException;
    public abstract void wakeup();
    public abstract Set keys();
    public abstract Set selectedKeys();
}

        选择器维护了一个需要监控的通道的集合。一个给定的通道可以被注册到多于一个的选择器上,而且不需要知道它被注册了哪个 Selector 对象上。SelectableChannel 的 register() 将返回一个封装了两个对象的关系的选择键对象。

SelectionKey 的相关 API 方法:
public abstract class SelectionKey {
    public static final int OP_READ;
    public static final int OP_WRITE;
    public static final int OP_CONNECT;
    public static final int OP_ACCEPT;
    public abstract SelectableChannel channel();
    public abstract Selector selector();
    public abstract void cancel();
    public abstract boolean isValid();
    public abstract int interestOps();
    public abstract void interestOps(int ops);
    public abstract int readyOps();
    public final boolean isReadable();
    public final boolean isWritable();
    public final boolean isConnectable();
    public final boolean isAcceptable();
    public final Object attach(Object ob);
    public final Object attachment();
}

        选择器才是提供管理功能的对象,而不是可选择通道对象。选择器对象对注册到它之上的通道执行就绪选择,并管理选择键。

    ◇ 建立选择器
        来看一段简短的代码,以便能够帮助我们将所有东西放到一个特定的上下文中去理解。为了建立监控三个 Socket 通道的选择器,你需要做像这样的事情:
Selector selector = Selector.open();
channel1.register(selector, SelectionKey.OP_READ);
channel2.register(selector, SelectionKey.OP_WRITE);
channel3.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
// Wait up to 10 seconds for a channel to become ready
readyCount = selector.select(10000);

        上面的代码创建了一个新的选择器,然后将这三个(已经存在的) socket 通道注册到选择器上,而且感兴趣的操作各不相同。 select() 方法在将线程置于睡眠状态,直到这些刚兴趣的事情中的操作中的一个发生或者 10 秒钟的时间过去。

        Selector 对象是通过调用静态工厂方法 open() 来实例化的。选择器不是像通道或流(stream)那样的基本 I/O 对象:数据从来没有通过它们进行传递。当你不再使用 Selector 时,需要调用 close() 方法来释放它可能占用的资源并将所有相关的选择键设置为无效。一旦一个选择器被关闭,试图调用它的大多数方法都将导致 ClosedSelectorException。注意 ClosedSelectorException 是一个运行时的)错误。你可以通过 isOpen() 方法来测试一个选择器是否处于被打开的状态。

        SelectableChannel 的 register() 方法接受一个 Selector 对象作为参数,以及一个名为 ops 的整数参数。第二个参数表示所关心的通道操作。这是一个表示选择器在检查通道就绪状态时需要关心的操作的比特掩码。JDK 中有四种被定义的可选择操作:读(read),写(write),连接(connect)和接受(accept)。并非所有的操作都在所有的可选择通道上被支持。例如,SocketChannel 不支持 accept。试图注册不支持的操作将导致 IllegalArgumentException。你可以通过调用 SelectableChannel 的 validOps() 方法来获取特定的通道所支持的操作集合。
分享到:
评论

相关推荐

    Java视频教程 Java游戏服务器端开发 Netty NIO AIO Mina视频教程

    [第9节] Java NIO流-选择器操作.flv 四、Mina视频教程 00、Mina视频课程介绍.flv 01、Mina服务端helloWorld入门.flv 02、Mina客户端helloWorld入门.flv 03、Mina整体体系结构分析.flv 04、Mina学习之长短连接....

    Java NIO(通道+缓冲区+选择器)

    Java NIO通道:通道基础、文件通道、Socket通道、工具类 Java NIO缓冲区:基础、缓冲区(Buffer)、创建缓冲区、直接缓冲区(DirectByteBuffer) Java NIO选择器:核心概念、选择器使用、Demo、选择器深入、

    《NIO与Socket编程技术指南》高洪岩.zip

    非常详细地讲解了NIO中的缓冲区、通道、选择器、编码,以及使用Socket技术实现TCP/IP和UDP编程,细化到了演示全部SocketOption的特性,这对理解基于NIO和Socket技术为基础所开发的NIO框架是非常有好处的,本书以案例...

    netty学习:bio,nio到netty各种使用案例,包括基础使用案例,各api使用方法,零拷贝,websocket,群聊,私聊,编码,解码,自定义协议,protobuf等使用案例,rpc服务器,客户端等等学习

    jdk原生的React器编程模型(使用选择器)聊天室 零拷贝使用案例文件上传 netty的演进模型(3中React器使用案例线程池的添加时机)。 NioEventLoopGroup中的成员变量分析(线程池) ChannelHandlerContext和...

    wifi-direct-chat:使用Java Nio通道通过wifi直接进行点对点聊天应用

    Java NIO选择器和通道。 如今,Java NIO已被包括Netty在内的许多项目广泛使用。 它提供了用于编写可伸缩服务器的无阻塞IO设施。 Java NIO提供了用于缓冲​​传入数据的缓冲机制。 通道是通过管道在两个实体之间传输...

    Java 基础核心总结 +经典算法大全.rar

    选择器(Selectors) 选择键(SelectionKey) 示例:简易的客户端服务器通信 集合 集合框架总览 -、Iterator Iterable ListIterator 二、Map 和 Collection 接口Map 集合体系详解 HashMap LinkedHashMap TreeMap ...

    2017最新大数据架构师精英课程

    149_source的通道选择器-复制策略-multiplexing 150_source的数据流程 151_sinkgroup的处理器-loadbalance- ^6 B0 j4 Z5 f9 d 152_sinkgroup的处理器-failover) y- ^1 Y. ~5 s9 G8 S! ^! a5 o 153_kafka集群安装与...

    1_6_zh_CN.CHM

    定义了用于多路复用的、非阻塞 I/O 操作的选择器。 java.nio.channels.spi 用于 java.nio.channels 包的服务提供者类。 java.nio.charset 定义用来在字节和 Unicode 字符之间转换的 charset、解码器和编码器。 ...

    JDK_API_1_6_zh_CN_downcc.com.zip 良心一级分

    定义了用于多路复用的、非阻塞 I/O 操作的选择器。 java.nio.channels.spi 用于 java.nio.channels 包的服务提供者类。 java.nio.charset 定义用来在字节和 Unicode 字符之间转换的 charset、解码器和编码器。 ...

    java jdk-api-1.6 中文 chmd

    定义了用于多路复用的、非阻塞 I/O 操作的选择器。 java.nio.channels.spi 用于 java.nio.channels 包的服务提供者类。 java.nio.charset 定义用来在字节和 Unicode 字符之间转换的 charset、解码器和编码器。 ...

    java8源码-netty-learn:这是一个用于netty学习的工程

    java8 源码 netty-learn 这是一个用于netty学习的工程 ##NIO基础 三大组件 Channel & Buffer channel有点类似于stream,它...Selector选择器 Selector的作用就是配合一个线程来管理多个channel,获取这些channel上发生

    JAVA_API1.6文档(中文)

    定义了用于多路复用的、非阻塞 I/O 操作的选择器。 java.nio.channels.spi 用于 java.nio.channels 包的服务提供者类。 java.nio.charset 定义用来在字节和 Unicode 字符之间转换的 charset、解码器和编码器。 ...

    积分管理系统java源码-knowledge:这是我的知识,包括我所有已知的

    bio、nio和aio 类加载器 常用设计模式 模板模式 单例模式 & 多例模式 代理模式 策略模式 原型模式 工厂模式 委托 其他 Spring5 IOC容器设计原理及高级特性 AOP设计原理 FactoryBean和BeanFactory Spring事务处理机制...

    【白雪红叶】JAVA学习技术栈梳理思维导图.xmind

    选择 冒泡 插入 快速 归并 堆 桶 基数 常用算法 贪婪 回溯 剪枝 动态规划 数据挖掘算法 KMP算法 GZZ算法 HASH分桶 关联规则算法 APRORIVE算法 分布式 负载均衡 水平伸缩 集群 分片 Key-...

    java api最新7.0

    定义了用于多路复用的、非阻塞 I/O 操作的选择器。 java.nio.channels.spi 用于 java.nio.channels 包的服务提供者类。 java.nio.charset 定义用来在字节和 Unicode 字符之间转换的 charset、解码器和编码器。 java....

    JavaAPI1.6中文chm文档 part1

    定义了用于多路复用的、非阻塞 I/O 操作的选择器。 java.nio.channels.spi 用于 java.nio.channels 包的服务提供者类。 java.nio.charset 定义用来在字节和 Unicode 字符之间转换的 charset、解码器和编码器。 ...

    JavaAPI中文chm文档 part2

    定义了用于多路复用的、非阻塞 I/O 操作的选择器。 java.nio.channels.spi 用于 java.nio.channels 包的服务提供者类。 java.nio.charset 定义用来在字节和 Unicode 字符之间转换的 charset、解码器和编码器。 ...

    [Java参考文档]

    定义了用于多路复用的、非阻塞 I/O 操作的选择器。 java.nio.channels.spi 用于 java.nio.channels 包的服务提供者类。 java.nio.charset 定义用来在字节和 Unicode 字符之间转换的 charset、解码器和编码器。 ...

Global site tag (gtag.js) - Google Analytics