java.nio.channels.Selector介绍(Javadoc翻译)

Selector是多个SelectableChannel对象的多路复用器。//一个Selector对应多个SelectableChannel。
Selector对象可以通过调用Selector.open()方法创建,这将会使用系统默认的SelectorProvider来创建一个新的Selector。Selector对象也可以通过调用(自定义的SelectorProvider对象的)openSelector()方法创建。Selector会一直保持打开状态直到通过调用close()方法关闭它。
一个SelectionKey对象代表:一个SelectableChannel注册到一个Selector上。一个Selector维护着三个SelectionKey集合:

  • key set 包含所有SelectionKey的代表了当前所有Channel向Selector的注册。这个集合通过keys()方法获得。
  • selected-key set 包含了这样的一些SelectionKey:SelectionKey对应的Channel在之前的select过程中被检测到已经准备好至少一种操作,这种操作被定义在SelectionKey关注的操作集合中。//Channel向Selector注册时要指定关注的操作集,即SelectableChannel#register方法的第二个参数。这个集合通过调用selectedKeys()方法获得。这个集合总是key set 的子集。
  • cancelled-key set 包含了一些SelectionKey,它们已经被取消了,但是它们对应的Channel还没有取消注册。这个集合不可以直接访问。这个集合总是key set 的子集。
    这三个集合在新创建的Selector中都是空的。

当调用SelectableChannel#register方法的时候,一个SelectionKey会被加入到Selector的key set 中。被取消的SelectionKey会在select过程中从key set里移除。key set 本身不可以直接修改。

当一个SelectionKey被取消时,它会被加入到对应Selector的cancelled-key set 中,无论是通过关闭对应的Channel或调用SelectionKey#cancel方法。取消一个SelectionKey会导致它对应的Channel在下一次select过程中被取消注册,此时这个SelectionKey会从Selector的所有集合中移除。

SelectionKey会通过select加入selected-key set 。一个SelectionKey可以通过调用Set#remove方法或Iterator#remove方法(Iterator通过Set#iterator方法获得)直接从selected-key set 中移除。SelectionKey不会通过其他任何方式从selected-key set 中移除,//用完一次要移除。他们不会通过select自动被移除(作为select的副作用)。SelectionKey不能直接添加到selected-key set 中。

Selection

在每一次select过程中,SelectionKey可能会被添加到selected-key set 或从selected-key set 删除,且可能会从key setcancelled-key set 删除。select通过select(),select(long),selectNow()方法执行,它包括三步:

  1. 每一个在cancelled-key set 中的SelectionKey都会从三个集合中移除,它对应的Channel会被取消注册。这一步会清空cancelled-key set
  2. 查询底层操作系统,获取剩下的每个Channel在select开始时的准备状态;准备状态是指Channel对应的SelectionKey关注的操作集中,那些操作的准备状态。对于一个准备好进行至少一种操作的Channel,执行以下两个动作之一:
    1. 如果Channel对应的SelectionKey并非已存在于 selected-key set 中,那么这个SelectionKey会被添加进去,且这个SelectionKey的准备就绪操作集(SelectionKey#readyOps)会被修改为当前Channel确已准备好的操作。准备就绪操作集中任何之前的准备就绪信息记录都会被丢弃。
    2. 如果Channel对应的SelectionKey已存在于selected-key set 中,那么它的准备就绪操作集中会新增Channel准备好的操作。任何之前的准备就绪信息记录都会被保留;也可以说是操作系统返回的就绪集与当前SelectionKey的就绪集做按位与运算。
    如果再这一步开始时,key set 中所有的SelectionKey关注的操作集合都是空的,那么selected-key set 和SelectionKey的准备就绪操作集都不会被更新。
  3. 当步骤(2)进行时,如果有任何SelectionKey被添加到cancelled-key set 中,那么它们按步骤(1)进行处理。

select是否使线程阻塞等待到有Channel准备就绪,等待多长时间,这是三种select方法唯一的区别。

Concurrency

Selector自身可供多个线程安全的并发使用,但是它的SelectionKey集合不可以。

select会在Selector对象上,在key set ,在selected-key set 上按顺序同步。select也会在上面所说的步骤(1)和步骤(3)时的cancelled-key set 上同步,

在一次select过程中,对SelectionKey关注的操作集做改变不会在本次select中生效;这些改变会在下一次select时被观察到。

SelectionKey和Channel可能会在任何时候被取消和关闭。因此,存在于Selector键集中的SelectionKey并不意味着是有效(valid)的,其对应的Channel也不一定是打开(open)的。如果其他线程有可能取消SelectionKey或关闭Channel,应用程序代码应该小心地去同步和检查这些必要的条件。

一个阻塞在select()或select(long)方法上的线程可能会被另一个线程通过以下三种方式打断:

  • 调用Selector#wakeup方法
  • 调用Selector#close方法
  • 调用被阻塞线程的Thread#interrupt方法,在这种情况下,线程的中断状态会被设置,且对应Selector的wakeup方法会被调用。

close方法在Selector对象上,在三个键集上按顺序同步。//与select时一样

一个SelectionKey和selected-key set 通常不能安全的被多个并发线程使用。如果一个线程可能会直接修改键集,那么需要在键集上同步以控制访问。通过键集的Set#iterator方法得到的Iterator对象是fail-fast的:除了调用Iterator#remove方法外,如果集合在迭代器被创建后发生了改变,ConcurrentModificationException会被抛出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值