码迷,mamicode.com
首页 > 编程语言 > 详细

Java NIO Selector

时间:2016-04-23 15:02:13      阅读:367      评论:0      收藏:0      [点我收藏+]

标签:

最近学习<Java NIO>中的Selector,于是结合Selector的源码,写一点笔记。

 


 

一. Selector是什么

讲到Selector,就不能不提SelectableChannel,SelectionKey。它们的关系是:

 

 

                                             技术分享

  1. 选择器(Selector)

    选择器类管理着一个被注册的通道集合的信息和它们的就绪状态。

 

  2. 可选择通道(SelectableChannel)

    这个抽象类提供了实现通道的可选择性所需要的公共方法。它是所有支持就绪检查的

    通道类的父类。

    SelectableChannel可以被注册到Selector对象上,同时可以指定对那个选择器而言,

    那种操作是感兴趣的

注意:FileChannel 对象不是可选择的,因为它们没有继承 SelectableChannel

 

  3. 选择键(SelectionKey)

    选 择 键 封 装 了 特 定 的 通 道 与 特 定 的 选 择 器 的 注 册 关 系 。

 

 

二. Selector的集合

  每个Selector对象维护3个集合(Set),每个集合的元素都是选择键(SelectionKey)。

  1. ♦ 已注册的键 
    与选择器关联的已经注册的键的集合。!并不是所有注册过的键都仍然有效!
 
  a. 得到此集合,可以调用下面的方法:
public abstract Set<SelectionKey> keys();
  b. 想要将一个键直接添加到此集合(某一个selector的keyset),不支持!
  c. 想从这个集合直接删除某个key,不支持!
 
  2. ♦ 已选择的键 ♦
       这个集合的每个成员都是相关的通道被选择器(在前一个选择操作中)判断为已经准备好的,
    并且包含于键的interest 集合中的操作。是已注册的键的集合的子集。
 
     a. 得到此集合,可以调用下面的方法:
public abstract Set<SelectionKey> selectedKeys();

  b. 想要将一个键直接添加到此集合,不支持!

  c. 想从这个集合直接删除某个key,可以调用下面的方法:

java.util.Set.remove(Object o);
//或
java.util.Iterator.remove();

   3. ♦  已取消的键 ♦ 

    已注册的键的集合的子集,这个集合包含了cancel( )方法被调用过的键(这个键已经被无效化),

    但它们还没有被注销。

       一个键被取消,就会加到这个集合。取消可以通过:

      →关闭与键关联的那个通道

      →调用键的cancel()方法。

 

技术分享技术分享  在一个刚初始化的 Selector 对象中,这三个集合都是空的。

  从上面的总结看到,对于某些集合的操作为“不支持”的情况,可能让人不解。

  !!请注意!!

    “不支持”是指“直接”的操作。如我们不能这样做:

//错误代码!!
Set<SelectionKey> keyset = selector.keys(); keyset.clear();

 

那如何才能“间接”地操作?就需要先了解Selector的工作流程。

 

三. Selector的工作流程

  1. 打开一个Selector

Selector selector = Selector.open();
//此时selector是新建的(刚初始化),三个集合都是空的。

 

  2. 将通道注册到selector

channel1.register (selector, SelectionKey.OP_READ); 
channel2.register (selector, SelectionKey.OP_WRITE);
channel3.register (selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);  
//这里假设3个channel是已存在的
//此时,已注册集合包含3个键。
//已选择集合和已取消集合为空

 

  3. 调用selector.select()

selector.select();

 

  将执行以下检查

    A. 检查已取消的键的集合。如果非空,就删除另外2个集合中在此集合中有的键,

    当然相关的通道被注销。还有此集合被清空。

    B. 检查已注册的键的集合的键的interest集合。

 

  以上步骤称为“就绪条件”,然后底层操作系统将会根据刚才的条件去查询,

  来确定每个通道所关心的操作的真实就绪状态

 

  在确定通道就绪状态时:

    A. 对于还没准备好的通道,将不会执行任何操作。

    B. 对于那些至少已经准备好interest集合中的一种操作的通道,将会执行以下2种操作的一种:

      B1. 如果通道的键还没有处于已选择的键的集合,那么键的ready集合将被清空,然后表示

        操作系统发现的当前通道已经准备好的操作的比特掩码将被设置。

      B2. 如果键在已选择的键的集合中,键的 ready 集合将被表示操作系统发现的当前已经准备

        好的操作的比特掩码更新

 

下面是我画的示意图:

左图为Selector.select()执行前:

  a.  Channel注册到Selector,所以Selector的Keys集合中包含 Selection Key(记为K)。而K中指明了

    Channel为C 和Selector为S之间的注册关系。

  b.  K的Interest Ops值为Read,表示Channel对读操作感兴趣。请留意:此时,S中Selected Keys集合为空。

右图为Selector.select()执行后:

   K的Read Ops值为Read,表示Channel的读操作就绪。

   K被加到S中Selected Keys集合。

 技术分享               技术分享

 

  这里我补充2点:

    * selector.select()是系统调用。

    * 在select()调用后,才去改变“就绪条件”,是不会影响本次select()的结果。

 

  select()会使调用线程阻塞,当有下面的条件会返回

    * 一个或以上的通道就绪

    * 此select.wakeup()方法的调用

    * 调用线程被中断(interrupted)

  

  select()是有返回值的,只是返回的不是已选择的键的集合中键的个数

  而是在此次调用select()时,ready集合被改变的键的数目。

 

  4. 取得selector的selected keys

  第3步的select()方法执行后,Selector的Selected Keys被更新。然后我们就遍历这个集合。

  前面说过,获取这个集合可以用 selectKeys( )方法。

  遍历这个集合时,对每个键进行处理,然后将键从这个集合删除

  删除这一步很重要:

   因为Selector把Selection Key添加到Selected Keys集合后,它就不会删除这个Key。

   需要我们手动去删除,相当于我们告诉Selector,“在遍历时我们已经看到并处理完这个Key

   所指示的readyOps”,于是Selector就知道这个key所关联的那个通道上,相关的就绪条件已经

   没用了(因为我们处理完了),它就在下一次select()操作而这个key所关联的那个通道有新到来的

   就绪条件,就把key的readyOps清空并重新设置为反映新状态的值。

    

Java NIO Selector

标签:

原文地址:http://www.cnblogs.com/JHChen/p/5372087.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!