前面介绍过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. [知识点]Tarjan算法

    // 此博文为迁移而来,写于2015年4月14日,不代表本人现在的观点与看法.原始地址:http://blog.sina.com.cn/s/blog_6022c4720102vxnx.html UPD ...

  2. HTML-DOM零碎

    以下是取得集合,取得单个元素,取消红色"s" Document.getElementsByName("some") //IE无效Document.getElem ...

  3. Codeforces Beta Round #6 (Div. 2 Only)

    A,B,C都是水题... D题,直接爆搜.我换了好多姿势,其实最简单的方法,就能过. #include <cstdio> #include <string> #include ...

  4. Eclispe怎么给工作空间下的项目分组

    Eclispe怎么给工作空间下的项目分组 第一步,打开Java Working Set 第二步,添加分组 第三步,选择分组

  5. Mobile data

    1.Consume REST web services from app 2.De-serialize JSON into an in-memory object collection 3.Save ...

  6. 关闭CentOS不必要的开机启动项

    命令行: for i in `chkconfig --list |grep 3:on|awk '{print $1}' |grep -Ev "network|sshd|sysstat|ude ...

  7. github page 构建自己的页面

    新建一个仓库.命名为:<你的账号>.github.io 然后上传一个index.html即可 打开浏览器输入:<你的账号>.github.io 即可访问

  8. Mysql日期时间大全

    MySQL日期时间函数大全 DAYOFWEEK(date)  返回日期date是星期几(1=星期天,2=星期一,--7=星期六,ODBC标准)mysql> select DAYOFWEEK('1 ...

  9. BizTalk开发系列(十三) Schema设计之值约束

    XML Schema 的作用是定义 XML 文档的合法构建模块.在开发过程中有时需要对XML文档做精确的约束.以保证XMl数据的准确性. 今天我们以一个班级Sample来讲探讨一下如何在开发BizTa ...

  10. 百度Site App的uaredirect.js实现手机访问,自动跳转网站手机版

    以下为代码,可放置在网站foot底部文件,或者haead顶部文件,建议将代码放在网站顶部,这样可以实现手机访问立即跳转! <script src="http://siteapp.bai ...