深入了解java NIO之Selector(选择器)
作者:rickiyang 发布时间:2022-02-01 16:39:17
这一节我们将探索选择器(selectors)。选择器提供选择执行已经就绪的任务的能力,这使得多元 I/O 成为可能。就像在第一章中描述的那样,就绪选择和多元执行使得单线程能够有效率地同时管理多个 I/O 通道(channels)。C/C++代码的工具箱中,许多年前就已经有 select()和 poll()这两个POSIX(可移植性操作系统接口)系统调用可供使用了。许过操作系统也提供相似的功能,但对Java 程序员来说,就绪选择功能直到 JDK 1.4 才成为可行的方案。
下面我们来使用选择器:
通过 Selector.open()方法, 我们可以创建一个选择器:
Selector selector = Selector.open();
将 Channel 注册到选择器中:
channel.configureBlocking(false);
SelectionKey key = channel.register(selector, SelectionKey.OP_READ);
注意, 如果一个 Channel 要注册到 Selector 中, 那么这个 Channel 必须是非阻塞的, 即channel.configureBlocking(false);因为 Channel 必须要是非阻塞的, 因此 FileChannel 不能够使用选择器, 因为 FileChannel 都是阻塞的.
注意到, 在使用 Channel.register()方法时, 第二个参数指定了我们对 Channel 的什么类型的事件感兴趣, 这些事件有:
Connect, 即连接事件(TCP 连接), 对应于SelectionKey.OP_CONNECT
Accept, 即确认事件, 对应于SelectionKey.OP_ACCEPT
Read, 即读事件, 对应于SelectionKey.OP_READ, 表示 buffer 可读.
Write, 即写事件, 对应于SelectionKey.OP_WRITE, 表示 buffer 可写.
一个 Channel发出一个事件也可以称为 对于某个事件, Channel 准备好了. 因此一个 Channel 成功连接到了另一个服务器也可以被称为 connect ready.
我们可以使用或运算|来组合多个事件, 例如:
int interestSet = SelectionKey.OP_READ | SelectionKey.OP_WRITE;
注意, 一个 Channel 仅仅可以被注册到一个 Selector 一次, 如果将 Channel 注册到 Selector 多次, 那么其实就是相当于更新 SelectionKey 的 interest set. 例如:
channel.register(selector, SelectionKey.OP_READ);
channel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
上面的 channel 注册到同一个 Selector 两次了, 那么第二次的注册其实就是相当于更新这个 Channel 的 interest set 为 SelectionKey.OP_READ | SelectionKey.OP_WRITE.
但是Java NIO的selector允许一个单一线程监听多个channel输入。我们可以注册多个channel到selector上,然后然后用一个线程来挑出一个处于可读或者可写状态的channel。selector机制使得单线程管理多个channel变得容易。
下面我们写一个完整的例子,看一下Selector的用法:
//创建选择器
Selector selector = Selector.open();
channel.configureBlocking(false);
//注册通道
SelectionKey key = channel.register(selector, SelectionKey.OP_READ);
while(true) {
//查看selector中的key是否准备好
int readyChannels = selector.select();
//小于0超时,等于0没准备好,大于0已经准备完毕
if(readyChannels == 0) continue;
//获取选择器中的key
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> 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();
}
}
选择器的使用还有很多的细节,我们应该多查看api文档了解各个方法的用法。下一节我们做一个综合练习,总结一下NIO的使用。
来源:https://www.cnblogs.com/rickiyang/p/11074240.html


猜你喜欢
- 本人一直喜欢左手使用鼠标,但有时候同事会临时进行操作,还得在控制面板里进行更改,比较不便,何不编写一个控制台程序,双击一下即可切换左右键 代
- Java面向对象之猜拳游戏,供大家参考,具体内容如下1 要求与电脑进行猜拳并记录分数。2 Computer.java 源代码(电脑自动随机出
- 本文实例讲述了Java排序算法总结之希尔排序。分享给大家供大家参考。具体分析如下:前言:希尔排序(Shell Sort)是插入排序的一种。是
- 本文主要介绍了C# 泛型字典 Dictionary的使用详解,分享给大家,具体如下:泛型最常见的用途是泛型集合,命名空间System.Col
- 可以用于简单的过期订单取消支付、7天自动收货场景中1、Spring Boot整合redis 参考https://www.jb51.net/a
- 目录Web服务器技术讲解PHP:JSP/ServletWeb服务器IISTomcatJAVA jdk中的内容TomcatTomcat根目录下
- 转成 Base64 形式的 System.String:string a = "base64字符串与普通字符串互转";
- 项目代码:https://github.com/bruceq/supermarket项目结构:依赖关系:common:公共层,无依赖dao:
- 本文实例为大家分享了Android实现签名涂鸦手写板的具体代码,供大家参考,具体内容如下布局文件<?xml version="
- 不可变对象不可变(immutable): 即对象一旦被创建初始化后,它们的值就不能被改变,之后的每次改变都会产生一个新对象。var str=
- 准备过程:在电脑桌面 右键点击 “此电脑”的“属性”选项选择“高级系统设置”选项点击下面的“环境变量”选项配置过程:点击“系统变量”下面的”
- P代表(Profiles配置文件)在<profiles>指定的<id>中,可以通过-P进行传递或者赋值。假如pom.
- 这篇文章主要介绍了spring boot 2整合swagger-ui过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的
- 下面是android SDK中API中的主要java包的功能简介: android.app :提供高层的程序模型、提供基本的运行环
- java中的前加加++和后加加++,有很多人搞的很晕,不太明白!今天我举几个例子说明下前++和后++的区别!其实大家只要记住一句话就可以了,
- 1.MyBatisX插件在使用mybatis或者mybatis-plus时,我们可以安装IDEA的MyBatis的插件 - MyBatisX
- 简述SpringBoot对Spring的的使用做了全面的封装,使用SpringBoot大大加快了开发进程,但是如果不了解Spring的特性,
- 互斥锁(Mutex)互斥锁是一个互斥的同步对象,意味着同一时间有且仅有一个线程可以获取它。互斥锁可适用于一个共享资源每次只能被一个线程访问的
- 本文主要介绍了Java实现雪花算法(snowflake),分享给大家,具体如下:简单描述最高位是符号位,始终为0,不可用。41位的时间序列,
- 一.背景项目中有个需求大体意思是,上传一个word模板,根据word模板合成word文件,再将word文件转为pdf。二.方案选择1.Spi