Selector

321 阅读5分钟

【写在前面】 所谓读源码,三分看代码,七分看注释。英语不好怎么办,我帮你翻译!

package java.nio.channels  
public abstract class Selector  
extends Object  
implements Closeable  

一个SelectableChannel(可选择通道)对象的多路复用器(译者注:以下称Selector)。

多路复用器可以由这个类的open方法创建。使用的是系统默认的 selector provider去创建一个新的多路复用器。一个多路复用器也可以由自定义的provider(提供者)的openSlector方法创建。Selector会持续开启直到它通过调用close方法去关闭。

一个SelectionKey对象代表了有一个可选择通道在Selector上面的注册。一个Selector管理着三种select key(译者注:选择键)集合:

  • key集合包含的key代表着当前通道在Selector的注册。这个集合可以由keys方法返回。
  • selected-key集合是channel已经被检测到准备好至少一种定义在key的兴趣集合在预选择期间的操作的key的集合。这个集合可以由selectedKeys方法返回。这个集合永远是key set的子集合。
  • cancelled-key集合是已经取消但是它们的channel还没有注销的key的集合。这个集合不能直接访问。这个集合永远是key集合的子集合。

上面所有三种集合在Selector新创建的时候都是空的。

通过register方法注册一个channel的side effect(副作用,也可以译作:连带作用)就是一个key添加到Selector的key集合中。在选择操作期间,已取消的键会从key集合中移除。key集合自己不能直接修改。

当一个key是已经取消的时候,会添加到Selector的cancelled-key集合中,无论是关闭他的channel还是调用cancel方法。取消一个key会导致这个key的channel在下一次选择操作期间从Selector中deregistered(译者注:注销),并且同时会从所有三种key set中移除出该key。

一个key通过选择操作会添加到selected-key集合中。一个key可以通过调用集合的remove方法或者该集合内部iterator(译者注:迭代器)的remove方法直接从selected-key集合中删除。Key从selected-key集合中移除永远不会有其他方法,特别是这些key的移除作为一种选择操作的副作用。Key不能直接添加到selected-key集合中。

Selection(选择)

在每次选择操作期间,key可以被添加和移除,从一个Selector的selected-key集合中,并且可以从这个Selector的key集合和cancelled-key集合中移除。Selection是由select(),select(long)selectNow()方法执行,包含下列三个步骤:

  1. cancelled-key集合中的每个key从它所属的每个集合中删除,并且key的channel会注销,这个步骤可以让cancelled-key集合为空。
  2. 在选择操作开始时,底层操作系统会查询剩余通道执行任意定义在key的interest set(译者注:兴趣集合)的操作的准备情况的更新。对于一个准备好至少一种操作的channel来说,下面两种行为之一会执行:
  • 如果channel的key没有在selected-key集合中,那么他将被添加到集合中,并且它的准备操作集合被修改,以准确标识channel现已准备好的那些操作。之前任意记录在准备集合上面的准备信息都将被废弃。
  • 反之,一个channel的key已经在selected-key集合中,因此它的准备操作集合被修改,以标识该channel已经准备好任意新操作。之前任意记录在准备集合上面的准备信息都将被保存。换句话说,准备集合是由底层操作系统按位分割key的当前准备集合返回的。
    如果key set中所有的key在步骤开始的时候是空的兴趣集合,那么selected-key集合和任意这个key的准备操作集合都不会更新。
  1. 当步骤2进行中的时候,如果有任何key添加到cancelled-key集合中,那么他妈将按照步骤1进行处理。

一个选择操作是否阻塞以等待一个或多个channel准备好,如果是的话,等待多久是这三种selection方法的本质区别。

Concurrency(并发性)

Selector自身在多线程下的使用是安全的,然而,它的key set并不是(线程安全)的。 选择操作按照selector本身,key集合,selected-key集合的顺序上同步。当cancelled-key集合在步骤(1)和步骤(3)的时候,他们也会同步。

当一个选择操作在进行中的时候,对一个Selector的key的兴趣集合所做的更改不会对操作产生影响,他将会在下一次选择操作时看到(影响)。

在任意时候Key都可以取消以及关闭channel。因此Selector中的一个或多个key集合中存在一个key不意味着这个key就是有效的或者它的channel是打开的。应用程序代码应该小心同步,并且在必要时检查这些条件,在如果有其他线程会取消一个key或者关闭一个channel的可能的时候。

一个线程在select()select(long)方法上的阻塞,由其他线程通过下面三种方式,会导致发生中断:

  • 通过调用Selector的weakup方法
  • 通过调用Selector的close方法
  • 通过调用阻塞线程的interrupt方法,在这种情况下,他的中断状态将会被设置,而且Selector的weakup方法也将会被调用。

close方法在Selector上是同步的,并且所有三种key集合在一个选择操作时以一个相同的顺序。

一个Selector的key和selected-key集合通常来说在多线程下使用并不是线程安全的。如果一个线程会直接修改那些集合中的一个,那么就应该对这些集合本身进行同步控制以进行访问。这些集合的iterator方法返回的迭代器是快速失败的:如果在创建了迭代器之后修改了集合,以任何方式除了调用这个迭代器自己的remove方法,就会抛出一个java.util.ConcurrentModificationException

Since:1.4