模块  java.base
软件包  java.nio.channels

Class Selector

  • 实现的所有接口
    CloseableAutoCloseable
    已知直接子类:
    AbstractSelector

    public abstract class Selector
    extends Object
    implements Closeable
    多路复用器SelectableChannel对象。

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

    可选择通道的选择器注册由SelectionKey对象表示。 选择器维护三组选择键:

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

    • 选择的密钥集是一组密钥,使得检测到每个密钥的信道准备好用于在先前的选择操作期间在密钥的兴趣集中识别的至少一个操作,该操作在该集合中添加密钥或更新密钥。 该集由selectedKeys方法返回。 选定键集始终是键集的子集。

    • 取消密钥集是已取消但其通道尚未取消注册的密钥集。 此套装无法直接访问。 取消密钥集始终是密钥集的子集。

    在新创建的选择器中,所有三个组都是空的。

    将一个键添加到选择器的键集,作为通过通道的register方法注册通道的副作用 在选择操作期间,取消的密钥将从密钥集中删除。 密钥集本身不能直接修改。

    无论是通过关闭其通道还是通过调用其cancel方法,都会在取消选择器的取消键集时添加一个键。 取消密钥将导致其通道在下一个选择操作期间取消注册,此时密钥将从所有选择器的密钥集中删除。

    通过选择操作将键添加到选定键集。 可以通过调用set的remove方法或通过调用从该集合获得的iteratorremove方法,直接从所选键集中移除键。 可以通过调用set的clear方法从所选键集中删除所有键。 密钥可能无法直接添加到选定密钥集。

    选择

    选择操作向底层操作系统查询关于每个注册信道的准备情况的更新,以执行由其密钥的兴趣集标识的任何操作。 选择操作有两种形式:

    1. select()select(long) ,和selectNow()方法添加信道的密钥准备好执行操作来选择键集,或更新准备就绪操作在选择键集组键已经。

    2. select(Consumer)select(Consumer, long) ,和selectNow(Consumer)方法执行对已准备好执行操作各通道的键的动作 这些方法不会添加到选定键集。

    添加到所选键集的选择操作

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

    1. 取消密钥集中的每个密钥将从其所属的每个密钥集中删除,并且其通道被取消注册。 此步骤将取消的密钥设置为空。

    2. 查询基础操作系统以获得关于每个剩余信道的准备情况的更新,以执行在其选择操作开始时由其密钥的兴趣集识别的任何操作。 对于已准备好进行至少一个此类操作的通道,将执行以下两个操作之一:

      1. 如果通道的密钥不在选择密钥集中,则将其添加到该集合中,并修改其就绪操作集以准确识别现在报告该通道准备就绪的那些操作。 先前记录在就绪集中的任何准备就绪信息都被丢弃。

      2. 否则,通道的密钥已经在选择密钥集中,因此修改其就绪操作集以识别报告信道已准备好的任何新操作。 先前记录在就绪集中的任何准备信息都被保留; 换句话说,底层系统返回的就绪集按位顺序分离到密钥的当前就绪集中。

      如果在此步骤开始时设置的密钥中的所有密钥都具有空兴趣集,则所选密钥集和任何密钥的就绪操作集都不会更新。
    3. 如果在步骤(2)正在进行时将任何键添加到取消键组,则按步骤(1)处理它们。

    选择操作是否阻止等待一个或多个通道准备就绪,以及如果等待多长时间,这是三种选择方法之间唯一的本质区别。

    对所选键执行操作的选择操作

    在每个选择操作期间,可以从选择器的键,选择键和取消键组中移除键。 选择由执行select(Consumer)select(Consumer,long) ,并selectNow(Consumer)方法,以及包括三个步骤:

    1. 取消密钥集中的每个密钥将从其所属的每个密钥集中删除,并且其通道被取消注册。 此步骤将取消的密钥设置为空。

    2. 查询基础操作系统以获得关于每个剩余信道的准备情况的更新,以执行在其选择操作开始时由其密钥的兴趣集识别的任何操作。

      对于一个信道准备好至少一个这样的操作中,准备好操作设定的通道的键的设置,以确定准确的量,信道准备的操作和指定给该动作 select方法被调用来消耗通道的键。 先前记录在就绪集中的任何就绪信息在调用动作之前被丢弃。

      或者,在通道准备好进行多个操作的情况下,可以多次调用该动作 ,其中通道的键和就绪操作集被修改为通道准备就绪的操作的子集。 如果对同一个键多次调用该操作,则其就绪操作集永远不会包含在同一选择操作中先前调用该操作时包含在该集中的操作位。

    3. 如果在步骤(2)正在进行时将任何键添加到取消键组,则按步骤(1)处理它们。

    并发

    Selector及其密钥集可安全地供多个并发线程使用。 但是,它的选择键集和取消键集不是。

    选择操作按顺序在选择键本集上的选择器本身上同步。 它们还在上面的步骤(1)和(3)期间在取消的密钥集上同步。

    在选择操作正在进行时对选择器键的兴趣集所做的更改对该操作没有影响; 它们将在下一次选择操作中看到。

    密钥可能会被取消,渠道可能随时关闭。 因此,在一个或多个选择器的密钥集中存在密钥并不意味着密钥有效或其信道是开放的。 如果有可能另一个线程取消密钥或关闭一个通道,应用程序代码应该小心地同步并检查这些条件。

    在选择操作中被阻塞的线程可能会被以下三种方式之一的其他线程中断:

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

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

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

    close方法以与选择操作中相同的顺序在选择器及其选择键集上同步。

    Selector的密钥集对多个并发线程使用是安全的。 来自密钥集的检索操作通常不会阻塞,因此可能与添加到集合的新注册重叠,或者与从集合中移除密钥的选择操作的取消步骤重叠。 迭代器和分裂器在迭代器/分裂器创建时或之后的某个时刻返回反映集合状态的元素。 他们不扔ConcurrentModificationException

    通常,选择器的选定密钥集不能安全地供多个并发线程使用。 如果这样的线程可能直接修改集合,则应通过同步集合本身来控制访问。 由set iterator方法返回的迭代器是快速失败的:如果在创建迭代器之后修改了set,除了通过调用迭代器自己的remove方法之外,将抛出ConcurrentModificationException

    从以下版本开始:
    1.4
    另请参见:
    SelectableChannelSelectionKey
    • 构造方法详细信息

      • Selector

        protected Selector()
        初始化此类的新实例。
    • 方法详细信息

      • isOpen

        public abstract boolean isOpen()
        判断此选择器是否已打开。
        结果
        true当且仅当此选择器打开时
      • provider

        public abstract SelectorProvider provider()
        返回创建此通道的提供程序。
        结果
        创建此渠道的提供商
      • keys

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

        密钥集不能直接修改。 只有在取消密钥并且其通道已取消注册后,才会删除该密钥。 任何修改密钥集的尝试都将导致抛出UnsupportedOperationException

        该集是safe ,供多个并发线程使用。

        结果
        这个选择器的键集
        异常
        ClosedSelectorException - 如果关闭此选择器
      • selectedKeys

        public abstract Set<SelectionKey> selectedKeys()
        返回此选择器的selected-key集。

        密钥可以从选定密钥集中删除,但不能直接添加到所选密钥集。 任何将对象添加到密钥集的尝试都将导致抛出UnsupportedOperationException

        所选键集是not thread-safe

        结果
        此选择器的选定键集
        异常
        ClosedSelectorException - 如果关闭此选择器
      • selectNow

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

        此方法执行非阻塞selection operation 如果自上次选择操作后没有可选择的通道,则此方法立即返回零。

        调用此方法可清除先前对wakeup方法的任何调用的影响

        结果
        键的数量,可能为零,其准备操作集由选择操作更新
        异常
        IOException - 如果发生I / O错误
        ClosedSelectorException - 如果关闭此选择器
      • select

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

        此方法执行阻止selection operation 只有在选择了至少一个通道后,才会返回此选项,调用此选择器的wakeup方法,当前线程被中断,或者给定的超时时间到期,以先到者为准。

        此方法不提供实时保证:它通过调用Object.wait(long)方法来调度超时。

        参数
        timeout - 如果为正,则在等待通道准备就绪时,或多或少阻止最多timeout毫秒; 如果为零,则无限期阻止; 一定不要消极
        结果
        键的数量,可能为零,其就绪操作集已更新
        异常
        IOException - 如果发生I / O错误
        ClosedSelectorException - 如果关闭此选择器
        IllegalArgumentException - 如果timeout参数的值为负
      • select

        public abstract int select()
                            throws IOException
        选择一组键,其相应的通道已准备好进行I / O操作。

        此方法执行阻止selection operation 它仅在选择了至少一个通道后才会返回,调用此选择器的wakeup方法,或者当前线程被中断,以先到者为准。

        结果
        键的数量,可能为零,其就绪操作集已更新
        异常
        IOException - 如果发生I / O错误
        ClosedSelectorException - 如果关闭此选择器
      • select

        public int select​(Consumer<SelectionKey> action,
                          long timeout)
                   throws IOException
        对相应通道准备好进行I / O操作的键选择并执行操作。

        此方法执行阻止selection operation 它从查询只在选择的至少一个信道的操作系统被唤醒时,此选择器的wakeup方法被调用时,当前线程被中断,或者给定的超时期满,以先到者为准。

        使用每个通道的密钥调用指定的操作accept方法,该通道准备执行由其键的兴趣集标识的操作。 对于相同的密钥,可以多次调用accept方法,但是使用包含信道准备就绪的操作的子集的就绪操作集(如上所述)。 在选择器及其选定键集上同步时调用accept方法。 必须非常小心,以避免与同时在这些对象上同步的其他线程发生死锁。 选择操作通常不是可重入的,因此操作应该非常小心,不要在同一个选择器上尝试选择操作。 尝试重入选择操作时的行为是特定于实现的,因此未指定。 如果操作关闭选择器,则在操作完成时抛出ClosedSelectorException 不禁止该操作关闭在选择器中注册的频道,也不禁止取消键或更改键的兴趣组。 如果选择了某个通道,但在对该键执行操作之前取消了其键或更改了其兴趣集,那么它是否具有实现特定于是否调用该操作 (可以使用invalid键调用它)。 操作抛出的异常将转发给调用者。

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

        实现要求:
        默认实现从选定密钥集中删除所有密钥,使用给定的超时调用select(long) ,然后对添加到selected-key集的每个密钥执行操作。 默认实现不会检测执行重入选择操作的操作。 在完成默认实现时,所选键集可能为空,也可能不为空。
        参数
        action - 要执行的操作
        timeout - 如果为正,则在等待通道准备就绪时阻止最多timeout毫秒,或多或少; 如果为零,则无限期阻止; 一定不要消极
        结果
        消耗的唯一键的数量,可能为零
        异常
        IOException - 如果发生I / O错误
        ClosedSelectorException - 如果此选择器已关闭或已被操作关闭
        IllegalArgumentException - 如果timeout参数的值为负数
        从以下版本开始:
        11
      • select

        public int select​(Consumer<SelectionKey> action)
                   throws IOException
        对相应通道准备好进行I / O操作的键选择并执行操作。

        此方法执行阻止selection operation 它从查询只在选择的至少一个信道的操作系统被唤醒时,此选择器的wakeup方法被调用,或者当前的线程被中断,以先到者为准。

        此方法相当于调用2-arg select方法,超时为0以无限期阻塞。

        实现要求:
        默认实现调用2-arg select方法,超时为 0
        参数
        action - 要执行的操作
        结果
        消耗的唯一键的数量,可能为零
        异常
        IOException - 如果发生I / O错误
        ClosedSelectorException - 如果此选择器已关闭或已被操作关闭
        从以下版本开始:
        11
      • selectNow

        public int selectNow​(Consumer<SelectionKey> action)
                      throws IOException
        对相应通道准备好进行I / O操作的键选择并执行操作。

        此方法执行非阻塞selection operation

        调用此方法可清除先前对wakeup方法的任何调用的影响

        实现要求:
        默认实现从选定密钥集中删除所有密钥,调用selectNow() ,然后对添加到selected-key集的每个密钥执行操作。 默认实现不会检测执行重入选择操作的操作。 在完成默认实现时,所选键集可能为空,也可能不为空。
        参数
        action - 要执行的操作
        结果
        消耗的唯一键的数量,可能为零
        异常
        IOException - 如果发生I / O错误
        ClosedSelectorException - 如果此选择器已关闭或已被操作关闭
        从以下版本开始:
        11
      • wakeup

        public abstract Selector wakeup()
        导致尚未返回的第一个选择操作立即返回。

        如果在选择操作中当前阻止了另一个线程,则该调用将立即返回。 如果当前没有选择操作正在进行,那么下一次选择操作的调用将立即返回,除非同时调用selectNow()selectNow(Consumer) 在任何情况下,该调用返回的值可能都不为零。 随后的选择操作将像往常一样阻止,除非在此期间再次调用此方法。

        在两次连续选择操作之间多次调用此方法与仅调用一次具有相同的效果。

        结果
        这个选择器
      • close

        public abstract void close()
                            throws IOException
        关闭此选择器。

        如果一个线程当前在这个选择器的一个选择方法中被阻塞,那么它就像通过调用选择器的wakeup方法一样被中断。

        仍与此选择器关联的任何未取消的密钥无效,其通道已取消注册,并且释放与此选择器关联的任何其他资源。

        如果此选择器已关闭,则调用此方法无效。

        关闭选择器后,除了通过调用此方法或wakeup方法之外,任何进一步尝试使用它都将导致抛出ClosedSelectorException

        Specified by:
        close ,界面 AutoCloseable
        Specified by:
        close在界面 Closeable
        异常
        IOException - 如果发生I / O错误