所有类


java.nio.channels
类 Selector

java.lang.Object
  继承者 java.nio.channels.Selector
直接已知子类:
AbstractSelector

public abstract class Selector
   
   
   
   
   
extends Object

SelectableChannel 对象的多路复用器。

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

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

  • 键集 包含的键表示当前通道到此选择器的注册。此集合由 keys 方法返回。

  • 已选择键集 是这样一种键的集合,即在前一次选择操作期间,检测每个键的通道是否已经至少为该键的相关操作集所标识的一个操作准备就绪。此集合由 selectedKeys 方法返回。已选择键集始终是键集的一个子集。

  • 已取消键集 是已被取消但其通道尚未注销的键的集合。不可直接访问此集合。已取消键集始终是键集的一个子集。

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

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

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

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

选择

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

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

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

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

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

  3. 如果在此步骤开始时键集中的所有键都有空的相关集合,则不会更新已选择键集和任意键的准备就绪操作集。
  4. 如果在步骤 (2) 的执行过程中要将任意键添加到已取消键集中,则处理过程如步骤 (1)。

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

并发性

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

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

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

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

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

  • 通过调用选择器的 wakeup 方法,

  • 通过调用选择器的 close 方法,或者

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

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

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

从以下版本开始:
1.4
另请参见:
SelectableChannel, SelectionKey

构造方法摘要
protected Selector()
          初始化此类的一个新实例。
 
方法摘要
abstract  void close()
          关闭此选择器。
abstract  boolean isOpen()
          告知此选择器是否已打开。
abstract  Set<SelectionKey> keys()
          返回此选择器的键集。
static Selector open()
          打开一个选择器。
abstract  SelectorProvider provider()
          返回创建此通道的提供程序。
abstract  int select()
          选择一组键,其相应的通道已为 I/O 操作准备就绪。
abstract  int select(long timeout)
          选择一组键,其相应的通道已为 I/O 操作准备就绪。
abstract  Set<SelectionKey> selectedKeys()
          返回此选择器的已选择键集。
abstract  int selectNow()
          选择一组键,其相应的通道已为 I/O 操作准备就绪。
abstract  Selector wakeup()
          使尚未返回的第一个选择操作立即返回。
 
从类 java.lang.Object 继承的方法
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

构造方法详细信息

Selector

protected Selector()
初始化此类的一个新实例。

方法详细信息

open

public static Selector open()
                     throws IOException
打开一个选择器。

通过调用系统级默认 SelectorProvider 对象的 openSelector 方法来创建新的选择器。

返回:
新的选择器
抛出:
IOException - 如果发生 I/O 错误

isOpen

public abstract boolean isOpen()
告知此选择器是否已打开。

返回:
当且仅当此选择器已打开时才返回 true

provider

public abstract SelectorProvider provider()
返回创建此通道的提供程序。

返回:
创建此通道的提供程序

keys

public abstract Set<SelectionKey> keys()
返回此选择器的键集。

不可直接修改键集。仅在已取消某个键并且已注销其通道后才移除该键。试图修改键集会导致抛出 UnsupportedOperationException

键集是非线程安全的

返回:
此选择器的键集
抛出:
ClosedSelectorException - 如果此选择器已关闭

selectedKeys

public abstract Set<SelectionKey> selectedKeys()
返回此选择器的已选择键集。

可从已选择键集中移除键,但是无法直接添加键。试图向该键集中添加对象会导致抛出 UnsupportedOperationException

已选择键集是非线程安全的

返回:
此选择器的已选择键集
抛出:
ClosedSelectorException - 如果此选择器已关闭

selectNow

public abstract int selectNow()
                       throws IOException
选择一组键,其相应的通道已为 I/O 操作准备就绪。

此方法执行非阻塞的选择操作。如果自从前一次选择操作后,没有通道变成可选择的,则此方法直接返回零。

调用此方法会清除所有以前调用 wakeup 方法所得的结果。

返回:
由选择操作更新其准备就绪操作集的键的数目,该数目可能为零
抛出:
IOException - 如果发生 I/O 错误
ClosedSelectorException - 如果此选择器已关闭

select

public abstract int select(long timeout)
                    throws IOException
选择一组键,其相应的通道已为 I/O 操作准备就绪。

此方法执行处于阻塞模式的选择操作。仅在至少选择一个通道、调用此选择器的 wakeup 方法、当前的线程已中断,或者给定的超时期满(以先到者为准)后此方法才返回。

此方法不提供实时保证:它安排了超时时间,就像调用 Object.wait(long) 方法一样。

参数:
timeout - 如果为正,则在等待某个通道准备就绪时最多阻塞 timeout 毫秒;如果为零,则无限期地阻塞;必须为非负数
返回:
已更新其准备就绪操作集的键的数目,该数目可能为零
抛出:
IOException - 如果发生 I/O 错误
ClosedSelectorException - 如果此选择器已关闭
IllegalArgumentException - 如果 timeout 参数的值为负

微信小程序

微信扫一扫体验

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部