selector 的 问题

 

 

关于使用NIO过程中出现的问题,最为普遍的就是为什么没有请求时CPU的占用率为100%?出现这种问题的主要原因是注册了不感兴趣的事件,比如如果没有数据要发到客户端,而又注册了写事件(OP_WRITE),则在 Selector.select()上就会始终有事件出现,CPU就一直处理了,而此时select()应该是阻塞的。

 

 

 

public abstract class Selector

extends Object

SelectableChannel 对象的多路复用器。

可通过调用此类的 open 方法创建选择器,该方法将使用系统的默认选择器提供程序创建新的选择器。也可通过调用自定义选择器提供程序的 openSelector 方法来创建选择器。通过选择器的 close 方法关闭选择器之前,它一直保持打开状态。

通过 SelectionKey 对象来表示可选择通道到选择器的注册。选择器维护了三种选择键集:

  • 键集 包含的键表示当前通道到此选择器的注册。此集合由 keys 方法返回。
  • 已选择键集 是这样一种键的集合,即在前一次选择操作期间,检测每个键的通道是否已经至少为该键的相关操作集所标识的一个操作准备就绪。此集合由 selectedKeys 方法返回。已选择键集始终是键集的一个子集。
  • 已取消键集 是已被取消但其通道尚未注销的键的集合。不可直接访问此集合。已取消键集始终是键集的一个子集。

在新创建的选择器中,这三个集合都是空集合。

通过某个通道的 register 方法注册该通道时,所带来的副作用是向选择器的键集中添加了一个键。在选择操作期间从键集中移除已取消的键。键集本身是不可直接修改的。

不管是通过关闭某个键的通道还是调用该键的 cancel 方法来取消键,该键都被添加到其选择器的已取消键集中。取消某个键会导致在下一次选择操作期间注销该键的通道,而在注销时将从所有选择器的键集中移除该键。

通过选择操作将键添加到已选择键集中。可通过调用已选择键集的 remove 方法,或者通过调用从该键集获得的 iterator  remove 方法直接移除某个键。通过任何其他方式从不会将键从已选择键集中移除;特别是,它们不会因为影响选择操作而被移除。不能将键直接添加到已选择键集中。

选择

在每次选择操作期间,都可以将键添加到选择器的已选择键集以及从中将其移除,并且可以从其键集和已取消键集中将其移除。选择是由select()select(long)  selectNow() 方法执行的,执行涉及三个步骤:

1.     将已取消键集中的每个键从所有键集中移除(如果该键是键集的成员),并注销其通道。此步骤使已取消键集成为空集。

2.     在开始进行选择操作时,应查询基础操作系统来更新每个剩余通道的准备就绪信息,以执行由其键的相关集合所标识的任意操作。对于已为至少一个这样的操作准备就绪的通道,执行以下两种操作之一:

a.      如果该通道的键尚未在已选择键集中,则将其添加到该集合中,并修改其准备就绪操作集,以准确地标识那些通道现在已报告为之准备就绪的操作。丢弃准备就绪操作集中以前记录的所有准备就绪信息。

b.     如果该通道的键已经在已选择键集中,则修改其准备就绪操作集,以准确地标识所有通道已报告为之准备就绪的新操作。保留准备就绪操作集以前记录的所有准备就绪信息;换句话说,基础系统所返回的准备就绪操作集是和该键的当前准备就绪操作集按位分开 (bitwise-disjoined) 的。

如果在此步骤开始时键集中的所有键都有空的相关集合,则不会更新已选择键集和任意键的准备就绪操作集。

3.     如果在步骤 (2) 的执行过程中要将任意键添加到已取消键集中,则处理过程如步骤 (1)

是否阻塞选择操作以等待一个或多个通道准备就绪,如果这样做的话,要等待多久,这是三种选择方法之间的惟一本质差别。

并发性

选择器自身可由多个并发线程安全使用,但是其键集并非如此。

选择操作在选择器本身上、在键集上和在已选择键集上是同步的,顺序也与此顺序相同。在执行上面的步骤 (1) (3) 时,它们在已取消键集上也是同步的。

在执行选择操作的过程中,更改选择器键的相关集合对该操作没有影响;进行下一次选择操作才会看到此更改。

可在任意时间取消键和关闭通道。因此,在一个或多个选择器的键集中出现某个键并不意味着该键是有效的,也不意味着其通道处于打开状态。如果存在另一个线程取消某个键或关闭某个通道的可能性,那么应用程序代码进行同步时应该小心,并且必要时应该检查这些条件。

阻塞在 select()  select(long) 方法之一中的某个线程可能被其他线程以下列三种方式之一中断:

  • 通过调用选择器的 wakeup 方法,
  • 通过调用选择器的 close 方法,或者
  • 在通过调用已阻塞线程的 interrupt 方法的情况下,将设置其中断状态并且将调用该选择器的 wakeup 方法。

close 方法在选择器上是同步的,并且所有三个键集都与选择操作中的顺序相同。

一般情况下,选择器的键和已选择键集由多个并发线程使用是不安全的。如果这样的线程可以直接修改这些键集之一,那么应该通过对该键集本身进行同步来控制访问。这些键集的 iterator 方法所返回的迭代器是快速失败 的:如果在创建迭代器后以任何方式(调用迭代器自身的 remove 方法除外)修改键集,则会抛出 ConcurrentModificationException

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值