前面介绍过Channel、Buffer,后面的文章主要讲解Selector的实践以及实现原理,选择器的概念比起通道、缓冲区要复杂一些,并且选择器是NIO中最重要的一部分内容。

为什么使用Selector

  Selector又称为“选择器”,单个线程通过Selector可以管理多个SelectableChannel,实际应用中管理多个请求连接。对于操作系统来说,线程之间上下文切换的开销很大,而且每个线程都要占用系统的一些资源,比如内存,因此使用的线程越少越好。

一、Selector的创建

Selector s = Selector.open();

二、通道注册

  channel.configureBlocking(false);
SelectionKey key = channel.register(s, SelectionKey.OP_ACCEPT);

Channel与Selector配合使用,必须将通道注册到选择器上,通过调用SelectableChannel的register()方法。注册完成之后,会返回此通道向选择器注册的键。

注册的时候调用的是SelectableChannel,所以注册仅支持父类是SelectableChannel的通道类;另外通道要设置成非阻塞模式,所以FileChannel不能与Selector一起使用(因为FileChannel不能切换到非 阻塞模式),而socket通道可以

register(Selector sel,int ops)方法调用的是SelectableChannel的注册方法,其中第二个参数是一个interest集合,表示在通过Selector监听Channel时对什么事件感兴趣。事件分为以下四种:

1、Connect

2、Accept

3、Read

4、Write

通道触发了一个事件意思是该事件已经就绪:

1、某个channel成功连接到另一个服务器称为“连接就绪”;

2、一个server socket channel准备好接收新进入的连接称为“接收就绪”

3、一个有数据可读的通道可以说是“读就绪”

4、等待写数据的通道可以说是“写就绪”

三、SelectionKey

表示 SelectableChannelSelector 中的注册的标记,每次向选择器注册通道时就会创建一个选择键。选择键中包含的内容有:

1、interset集合

2、ready集合

3、Channel

4、Selector

一旦向Selector注册了一个或多个通道,就可以调用几个重载的select()方法,这些方法返回你所感兴趣的事件(如连接、接收、可读写)已经准备就绪的那些通道。

int n = selector.select();

select方法返回的int值表示有多少通道已经就绪。第一次调用select方法,如果有一个通道就绪,则返回1;如果再次调用select方法,此时另一个通道就绪了,它会再次返回1。我们可以通过Selector的selectedKeys的方法,访问“已选择键集”中的就绪通道

selector.selectedKeys()
  while(iterator.hasNext())
{
SelectionKey key = iterator.next();
//通道上是否有可接受的连接
if(key.isAcceptable())
{
ServerSocketChannel ssl = (ServerSocketChannel)key.channel();
SocketChannel scl = ssl.accept();
scl.configureBlocking(false);
scl.register(selector, SelectionKey.OP_READ);
}
//通道上是否有数据可读
else if(key.isReadable())
{
readDataFromSocket(key);
}
iterator.remove();
}

这个循环遍历键集中的每个键,并检测各个键对应的通道的就绪事件并做相应的处理。

我们要注意第17行,调用迭代器的remove方法。Selector不会自己从已选择键集中移除SelectionKey实例,必须要我们自己处理完通道时手动处理。下次该通道变成就绪时,Selector会再次将其放入已选择键集中。

四、WakeUp

某个线程调用select方法阻塞了,即使没有通道就绪,也有办法让其从select返回。只要让其它线程在第一个线程调用select方法的那个对象上调用selector.wakeup方法即可。阻塞在select方法上的线程立马返回。

五、Close

用完selector后调用其close方法会关闭Selector,且使其注册到该Selector上的所有SelectionKey实例无效。通道本身并不会关闭。

JAVA NIO系列(四) 选择器的更多相关文章

  1. Java NIO系列教程(四) Scatter 和 Gather

    Java NIO系列教程(四) Scatter 和 Gather Java NIO 开始支持 scatter/gather,scatter/gather 用于描述从 Channel(译者注:Chann ...

  2. Java NIO 系列教程(转)

    原文中说了最重要的3个概念,Channel 通道Buffer 缓冲区Selector 选择器其中Channel对应以前的流,Buffer不是什么新东西,Selector是因为nio可以使用异步的非堵塞 ...

  3. Java NIO系列教程(三) Channel之Socket通道

    目录: <Java NIO系列教程(二) Channel> <Java NIO系列教程(三) Channel之Socket通道> 在<Java NIO系列教程(二) Ch ...

  4. Java NIO系列教程(十一) Java NIO 与 IO

    Java NIO系列教程(十一) Java NIO与IO 当学习了 Java NIO 和 IO 的 API 后,一个问题马上涌入脑海: 我应该何时使用 IO,何时使用 NIO 呢?在本文中,我会尽量清 ...

  5. Java NIO系列教程(三-十二) Buffer

    原文链接     作者:Jakob Jenkov     译者:airu     校对:丁一 Java NIO中的Buffer用于和NIO通道进行交互.如你所知,数据是从通道读入缓冲区,从缓冲区写入到 ...

  6. Java NIO系列1-概观

    Java NIO系列1-概观 Java NIO.中间的N你既可以理解为(new),也就是新的IO,相对于java1.5之前的IO它确实是新的;也可以理解为(no-blocking),也就是非阻塞的IO ...

  7. Java NIO系列教程(七) selector原理 Epoll版的Selector

    目录: Reactor(反应堆)和Proactor(前摄器) <I/O模型之三:两种高性能 I/O 设计模式 Reactor 和 Proactor> <[转]第8章 前摄器(Proa ...

  8. [转]Java NIO 系列教程

    Java NIO提供了与标准IO不同的IO工作方式: Channels and Buffers(通道和缓冲区):标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(B ...

  9. Java NIO 系列教程 <转>

    Java NIO提供了与标准IO不同的IO工作方式: Channels and Buffers(通道和缓冲区):标准的IO基于字节流和字符流进行操作的,而NIO是基于通道(Channel)和缓冲区(B ...

  10. java NIO系列教程1

    ava NIO(New IO)是一个可以替代标准Java IO API的IO API(从Java 1.4开始),Java NIO提供了与标准IO不同的IO工作方式. Java NIO: Channel ...

随机推荐

  1. 【wikioi】2822 爱在心中

    题目链接 算法:Tarjan+dfs(最短路的都行,判连通而已) 先了解一下什么是Tarjan Tarjan算法用于求出图中所有的强连通分量. 转自NOCOW:点击打开链接 ============= ...

  2. 基于MINA构建简单高性能的NIO应用

    mina是非常好的C/S架构的java服务器,这里转了一篇关于它的使用感受. 前言MINA是Trustin Lee最新制作的Java通讯框架.通讯框架的主要作用是封装底层IO操作,提供高级的操作API ...

  3. html5 可以讓使用者輸入url網址 ,去play影片

    <html> <head> <title>Simple Video Example</title> <script> function pl ...

  4. jquery插件jquery.LightBox.js之点击放大图片并左右点击切换图片(仿相册插件)

    该插件乃本博客作者所写,目的在于提升作者的js能力,也给一些js菜鸟在使用插件时提供一些便利,老鸟就悠然地飞过吧. 此插件旨在实现目前较为流行的点击放大图片并左右点击切换图片的效果,您可以根据自己的实 ...

  5. ListView的HeaderView和Footer

    HeaderView介绍 HeaderView用法 属性中添加 ListView中属性listHeader和overScrollHeader区别: android:overScrollHeader=& ...

  6. [LintCode] Valid Palindrome 验证回文字符串

    Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignori ...

  7. Save vtkImageData to BMP Image 保存vtkImageData为图片

    在VTK中,我们有时候想要保存vtkImageData类的变量到一幅图片,可以使用如下的实例代码: #include <vtkBMPReader.h> #include <vtkBM ...

  8. TestStand与LabVIEW UI 交互

    交互起因 客户觉得TestStand界面复杂,希望一个简单的界面即可进行序列执行,采用LabVIEW调用TestStand引擎可实现快速设计,将TestStand拆解到LabVIEW.然而,这样做需要 ...

  9. JS的Touch事件们,触屏时的js事件

    丫的,终于找到了JS在平板电脑上的事件!!!   iphone.ipod Touch.ipad触屏时的js事件   1.Touch事件简介   pc上的web页面鼠标会产生onmousedown.on ...

  10. firebox httprequester 模拟请求

    获取下载插件 httprequester 模拟POST请求,必须点击Parameter Body 参数写法:abc=123&id=456 也可以选择Headers栏目添加